├── .github └── workflows │ └── python-package.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── README.md ├── bitcoin ├── __init__.py ├── base58.py ├── bech32.py ├── bloom.py ├── core │ ├── __init__.py │ ├── _bignum.py │ ├── contrib │ │ ├── __init__.py │ │ └── ripemd160.py │ ├── key.py │ ├── script.py │ ├── scripteval.py │ └── serialize.py ├── messages.py ├── net.py ├── rpc.py ├── segwit_addr.py ├── signature.py ├── signmessage.py ├── tests │ ├── __init__.py │ ├── data │ │ ├── base58_encode_decode.json │ │ ├── bech32_encode_decode.json │ │ ├── bech32_invalid.json │ │ ├── checkblock_invalid.json │ │ ├── checkblock_valid.json │ │ ├── script_invalid.json │ │ ├── script_valid.json │ │ ├── signmessage.json │ │ ├── tx_invalid.json │ │ └── tx_valid.json │ ├── fakebitcoinproxy.py │ ├── test_base58.py │ ├── test_bech32.py │ ├── test_bloom.py │ ├── test_checkblock.py │ ├── test_core.py │ ├── test_fakebitcoinproxy.py │ ├── test_key.py │ ├── test_messages.py │ ├── test_net.py │ ├── test_ripemd160.py │ ├── test_rpc.py │ ├── test_script.py │ ├── test_scripteval.py │ ├── test_segwit.py │ ├── test_serialize.py │ ├── test_signmessage.py │ ├── test_transactions.py │ └── test_wallet.py └── wallet.py ├── doc ├── .gitignore ├── Makefile ├── _static │ └── .placeholder ├── _templates │ └── .placeholder ├── bitcoin.core.rst ├── bitcoin.rst ├── conf.py ├── index.rst └── make.bat ├── examples ├── bip-0070-payment-protocol.py ├── make-bootstrap-rpc.py ├── msg-serializable.py ├── publish-text.py ├── send-addrs-msg.py ├── sign-message.py ├── spend-p2pkh-txout.py ├── spend-p2sh-txout.py ├── spend-p2wpkh.py ├── spend-p2wsh-txout.py ├── ssl-rpc-connection.py └── timestamp-op-ret.py ├── release-notes.md ├── runtests.sh ├── setup.py └── tox.ini /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ "master" ] 9 | pull_request: 10 | branches: [ "master" ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.9", "3.10", "3.11"] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v3 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install flake8 pytest 31 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 32 | - name: Lint with flake8 33 | run: | 34 | # stop the build if there are Python syntax errors or undefined names 35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 38 | - name: Test with pytest 39 | run: | 40 | pytest 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw? 2 | *.pyc 3 | 4 | local*.cfg 5 | 6 | .coverage 7 | .tox/ 8 | build/ 9 | htmlcov/ 10 | python_bitcoinlib.egg-info/ 11 | dist/ 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | git: 2 | depth: 9999999 3 | language: python 4 | python: 5 | - "3.4" 6 | - "3.5" 7 | - "3.6" 8 | - "3.7" 9 | # command to run tests 10 | script: python3 -m unittest discover -v 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | python-bitcoinlib is free software: you can redistribute it and/or modify it 2 | under the terms of the GNU Lesser General Public License as published by the 3 | Free Software Foundation, either version 3 of the License, or (at your option) 4 | any later version. 5 | 6 | python-bitcoinlib is distributed in the hope that it will be useful, but 7 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 9 | below for more details. 10 | 11 | 12 | 13 | GNU LESSER GENERAL PUBLIC LICENSE 14 | Version 3, 29 June 2007 15 | 16 | Copyright (C) 2007 Free Software Foundation, Inc. 17 | Everyone is permitted to copy and distribute verbatim copies 18 | of this license document, but changing it is not allowed. 19 | 20 | 21 | This version of the GNU Lesser General Public License incorporates 22 | the terms and conditions of version 3 of the GNU General Public 23 | License, supplemented by the additional permissions listed below. 24 | 25 | 0. Additional Definitions. 26 | 27 | As used herein, "this License" refers to version 3 of the GNU Lesser 28 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 29 | General Public License. 30 | 31 | "The Library" refers to a covered work governed by this License, 32 | other than an Application or a Combined Work as defined below. 33 | 34 | An "Application" is any work that makes use of an interface provided 35 | by the Library, but which is not otherwise based on the Library. 36 | Defining a subclass of a class defined by the Library is deemed a mode 37 | of using an interface provided by the Library. 38 | 39 | A "Combined Work" is a work produced by combining or linking an 40 | Application with the Library. The particular version of the Library 41 | with which the Combined Work was made is also called the "Linked 42 | Version". 43 | 44 | The "Minimal Corresponding Source" for a Combined Work means the 45 | Corresponding Source for the Combined Work, excluding any source code 46 | for portions of the Combined Work that, considered in isolation, are 47 | based on the Application, and not on the Linked Version. 48 | 49 | The "Corresponding Application Code" for a Combined Work means the 50 | object code and/or source code for the Application, including any data 51 | and utility programs needed for reproducing the Combined Work from the 52 | Application, but excluding the System Libraries of the Combined Work. 53 | 54 | 1. Exception to Section 3 of the GNU GPL. 55 | 56 | You may convey a covered work under sections 3 and 4 of this License 57 | without being bound by section 3 of the GNU GPL. 58 | 59 | 2. Conveying Modified Versions. 60 | 61 | If you modify a copy of the Library, and, in your modifications, a 62 | facility refers to a function or data to be supplied by an Application 63 | that uses the facility (other than as an argument passed when the 64 | facility is invoked), then you may convey a copy of the modified 65 | version: 66 | 67 | a) under this License, provided that you make a good faith effort to 68 | ensure that, in the event an Application does not supply the 69 | function or data, the facility still operates, and performs 70 | whatever part of its purpose remains meaningful, or 71 | 72 | b) under the GNU GPL, with none of the additional permissions of 73 | this License applicable to that copy. 74 | 75 | 3. Object Code Incorporating Material from Library Header Files. 76 | 77 | The object code form of an Application may incorporate material from 78 | a header file that is part of the Library. You may convey such object 79 | code under terms of your choice, provided that, if the incorporated 80 | material is not limited to numerical parameters, data structure 81 | layouts and accessors, or small macros, inline functions and templates 82 | (ten or fewer lines in length), you do both of the following: 83 | 84 | a) Give prominent notice with each copy of the object code that the 85 | Library is used in it and that the Library and its use are 86 | covered by this License. 87 | 88 | b) Accompany the object code with a copy of the GNU GPL and this license 89 | document. 90 | 91 | 4. Combined Works. 92 | 93 | You may convey a Combined Work under terms of your choice that, 94 | taken together, effectively do not restrict modification of the 95 | portions of the Library contained in the Combined Work and reverse 96 | engineering for debugging such modifications, if you also do each of 97 | the following: 98 | 99 | a) Give prominent notice with each copy of the Combined Work that 100 | the Library is used in it and that the Library and its use are 101 | covered by this License. 102 | 103 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 104 | document. 105 | 106 | c) For a Combined Work that displays copyright notices during 107 | execution, include the copyright notice for the Library among 108 | these notices, as well as a reference directing the user to the 109 | copies of the GNU GPL and this license document. 110 | 111 | d) Do one of the following: 112 | 113 | 0) Convey the Minimal Corresponding Source under the terms of this 114 | License, and the Corresponding Application Code in a form 115 | suitable for, and under terms that permit, the user to 116 | recombine or relink the Application with a modified version of 117 | the Linked Version to produce a modified Combined Work, in the 118 | manner specified by section 6 of the GNU GPL for conveying 119 | Corresponding Source. 120 | 121 | 1) Use a suitable shared library mechanism for linking with the 122 | Library. A suitable mechanism is one that (a) uses at run time 123 | a copy of the Library already present on the user's computer 124 | system, and (b) will operate properly with a modified version 125 | of the Library that is interface-compatible with the Linked 126 | Version. 127 | 128 | e) Provide Installation Information, but only if you would otherwise 129 | be required to provide such information under section 6 of the 130 | GNU GPL, and only to the extent that such information is 131 | necessary to install and execute a modified version of the 132 | Combined Work produced by recombining or relinking the 133 | Application with a modified version of the Linked Version. (If 134 | you use option 4d0, the Installation Information must accompany 135 | the Minimal Corresponding Source and Corresponding Application 136 | Code. If you use option 4d1, you must provide the Installation 137 | Information in the manner specified by section 6 of the GNU GPL 138 | for conveying Corresponding Source.) 139 | 140 | 5. Combined Libraries. 141 | 142 | You may place library facilities that are a work based on the 143 | Library side by side in a single library together with other library 144 | facilities that are not Applications and are not covered by this 145 | License, and convey such a combined library under terms of your 146 | choice, if you do both of the following: 147 | 148 | a) Accompany the combined library with a copy of the same work based 149 | on the Library, uncombined with any other library facilities, 150 | conveyed under the terms of this License. 151 | 152 | b) Give prominent notice with the combined library that part of it 153 | is a work based on the Library, and explaining where to find the 154 | accompanying uncombined form of the same work. 155 | 156 | 6. Revised Versions of the GNU Lesser General Public License. 157 | 158 | The Free Software Foundation may publish revised and/or new versions 159 | of the GNU Lesser General Public License from time to time. Such new 160 | versions will be similar in spirit to the present version, but may 161 | differ in detail to address new problems or concerns. 162 | 163 | Each version is given a distinguishing version number. If the 164 | Library as you received it specifies that a certain numbered version 165 | of the GNU Lesser General Public License "or any later version" 166 | applies to it, you have the option of following the terms and 167 | conditions either of that published version or of any later version 168 | published by the Free Software Foundation. If the Library as you 169 | received it does not specify a version number of the GNU Lesser 170 | General Public License, you may choose any version of the GNU Lesser 171 | General Public License ever published by the Free Software Foundation. 172 | 173 | If the Library as you received it specifies that a proxy can decide 174 | whether future versions of the GNU Lesser General Public License shall 175 | apply, that proxy's public statement of acceptance of any version is 176 | permanent authorization for you to choose that version for the 177 | Library. 178 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE README.md 2 | graft bitcoin/tests/data/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-bitcoinlib 2 | 3 | This Python3 library provides an easy interface to the bitcoin data 4 | structures and protocol. The approach is low-level and "ground up", with a 5 | focus on providing tools to manipulate the internals of how Bitcoin works. 6 | 7 | "The Swiss Army Knife of the Bitcoin protocol." - Wladimir J. van der Laan 8 | 9 | 10 | ## Requirements 11 | 12 | sudo apt-get install libssl-dev 13 | 14 | The RPC interface, `bitcoin.rpc`, should work with Bitcoin Core v24.0 or later. 15 | Older versions may work but there do exist some incompatibilities. 16 | 17 | 18 | ## Structure 19 | 20 | Everything consensus critical is found in the modules under bitcoin.core. This 21 | rule is followed pretty strictly, for instance chain parameters are split into 22 | consensus critical and non-consensus-critical. 23 | 24 | bitcoin.core - Basic core definitions, datastructures, and 25 | (context-independent) validation 26 | bitcoin.core.key - ECC pubkeys 27 | bitcoin.core.script - Scripts and opcodes 28 | bitcoin.core.scripteval - Script evaluation/verification 29 | bitcoin.core.serialize - Serialization 30 | 31 | In the future the bitcoin.core may use the Satoshi sourcecode directly as a 32 | library. Non-consensus critical modules include the following: 33 | 34 | bitcoin - Chain selection 35 | bitcoin.base58 - Base58 encoding 36 | bitcoin.bloom - Bloom filters (incomplete) 37 | bitcoin.net - Network communication (in flux) 38 | bitcoin.messages - Network messages (in flux) 39 | bitcoin.rpc - Bitcoin Core RPC interface support 40 | bitcoin.wallet - Wallet-related code, currently Bitcoin address and 41 | private key support 42 | 43 | Effort has been made to follow the Satoshi source relatively closely, for 44 | instance Python code and classes that duplicate the functionality of 45 | corresponding Satoshi C++ code uses the same naming conventions: CTransaction, 46 | CBlockHeader, nValue etc. Otherwise Python naming conventions are followed. 47 | 48 | 49 | ## Mutable vs. Immutable objects 50 | 51 | Like the Bitcoin Core codebase CTransaction is immutable and 52 | CMutableTransaction is mutable; unlike the Bitcoin Core codebase this 53 | distinction also applies to COutPoint, CTxIn, CTxOut, and CBlock. 54 | 55 | 56 | ## Endianness Gotchas 57 | 58 | Rather confusingly Bitcoin Core shows transaction and block hashes as 59 | little-endian hex rather than the big-endian the rest of the world uses for 60 | SHA256. python-bitcoinlib provides the convenience functions x() and lx() in 61 | bitcoin.core to convert from big-endian and little-endian hex to raw bytes to 62 | accommodate this. In addition see b2x() and b2lx() for conversion from bytes to 63 | big/little-endian hex. 64 | 65 | 66 | ## Module import style 67 | 68 | While not always good style, it's often convenient for quick scripts if 69 | `import *` can be used. To support that all the modules have `__all__` defined 70 | appropriately. 71 | 72 | 73 | # Example Code 74 | 75 | See `examples/` directory. For instance this example creates a transaction 76 | spending a pay-to-script-hash transaction output: 77 | 78 | $ PYTHONPATH=. examples/spend-p2sh-txout.py 79 | 80 | 81 | 82 | ## Selecting the chain to use 83 | 84 | Do the following: 85 | 86 | import bitcoin 87 | bitcoin.SelectParams(NAME) 88 | 89 | Where NAME is one of 'testnet', 'mainnet', 'signet', or 'regtest'. The chain currently 90 | selected is a global variable that changes behavior everywhere, just like in 91 | the Satoshi codebase. 92 | 93 | 94 | ## Unit tests 95 | 96 | Under bitcoin/tests using test data from Bitcoin Core. To run them: 97 | 98 | python3 -m unittest discover 99 | 100 | Alternately, if Tox (see https://tox.readthedocs.org/) is available on your 101 | system, you can run unit tests for multiple Python versions: 102 | 103 | ./runtests.sh 104 | 105 | HTML coverage reports can then be found in the htmlcov/ subdirectory. 106 | 107 | 108 | ## Documentation 109 | 110 | Sphinx documentation is in the "doc" subdirectory. Run "make help" from there 111 | to see how to build. You will need the Python "sphinx" package installed. 112 | 113 | Currently this is just API documentation generated from the code and 114 | docstrings. Higher level written docs would be useful, perhaps starting with 115 | much of this README. Pages are written in reStructuredText and linked from 116 | index.rst. 117 | -------------------------------------------------------------------------------- /bitcoin/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import bitcoin.core 14 | 15 | # Note that setup.py can break if __init__.py imports any external 16 | # dependencies, as these might not be installed when setup.py runs. In this 17 | # case __version__ could be moved to a separate version.py and imported here. 18 | __version__ = '0.12.2' 19 | 20 | class MainParams(bitcoin.core.CoreMainParams): 21 | MESSAGE_START = b'\xf9\xbe\xb4\xd9' 22 | DEFAULT_PORT = 8333 23 | RPC_PORT = 8332 24 | DNS_SEEDS = (('bitcoin.sipa.be', 'seed.bitcoin.sipa.be'), 25 | ('bluematt.me', 'dnsseed.bluematt.me'), 26 | ('dashjr.org', 'dnsseed.bitcoin.dashjr.org'), 27 | ('bitcoinstats.com', 'seed.bitcoinstats.com'), 28 | ('petertodd.org', 'seed.btc.petertodd.net'), 29 | ('xf2.org', 'bitseed.xf2.org'), 30 | ('bitcoin.jonasschnelli.ch', 'seed.bitcoin.jonasschnelli.ch')) 31 | BASE58_PREFIXES = {'PUBKEY_ADDR':0, 32 | 'SCRIPT_ADDR':5, 33 | 'SECRET_KEY' :128} 34 | BECH32_HRP = 'bc' 35 | 36 | class TestNetParams(bitcoin.core.CoreTestNetParams): 37 | MESSAGE_START = b'\x0b\x11\x09\x07' 38 | DEFAULT_PORT = 18333 39 | RPC_PORT = 18332 40 | DNS_SEEDS = (('testnetbitcoin.jonasschnelli.ch', 'testnet-seed.bitcoin.jonasschnelli.ch'), 41 | ('petertodd.org', 'seed.tbtc.petertodd.net'), 42 | ('bluematt.me', 'testnet-seed.bluematt.me'), 43 | ('bitcoin.schildbach.de', 'testnet-seed.bitcoin.schildbach.de')) 44 | BASE58_PREFIXES = {'PUBKEY_ADDR':111, 45 | 'SCRIPT_ADDR':196, 46 | 'SECRET_KEY' :239} 47 | BECH32_HRP = 'tb' 48 | 49 | class SigNetParams(bitcoin.core.CoreSigNetParams): 50 | MESSAGE_START = b'\x0a\x03\xcf\x40' 51 | DEFAULT_PORT = 38333 52 | RPC_PORT = 38332 53 | DNS_SEEDS = (("signet.bitcoin.sprovoost.nl", "seed.signet.bitcoin.sprovoost.nl")) 54 | BASE58_PREFIXES = {'PUBKEY_ADDR':111, 55 | 'SCRIPT_ADDR':196, 56 | 'SECRET_KEY' :239} 57 | 58 | BECH32_HRP = 'tb' 59 | 60 | class RegTestParams(bitcoin.core.CoreRegTestParams): 61 | MESSAGE_START = b'\xfa\xbf\xb5\xda' 62 | DEFAULT_PORT = 18444 63 | RPC_PORT = 18443 64 | DNS_SEEDS = () 65 | BASE58_PREFIXES = {'PUBKEY_ADDR':111, 66 | 'SCRIPT_ADDR':196, 67 | 'SECRET_KEY' :239} 68 | BECH32_HRP = 'bcrt' 69 | 70 | """Master global setting for what chain params we're using. 71 | 72 | However, don't set this directly, use SelectParams() instead so as to set the 73 | bitcoin.core.params correctly too. 74 | """ 75 | #params = bitcoin.core.coreparams = MainParams() 76 | params = MainParams() 77 | 78 | def SelectParams(name): 79 | """Select the chain parameters to use 80 | 81 | name is one of 'mainnet', 'testnet', or 'regtest' 82 | 83 | Default chain is 'mainnet' 84 | """ 85 | global params 86 | bitcoin.core._SelectCoreParams(name) 87 | if name == 'mainnet': 88 | params = bitcoin.core.coreparams = MainParams() 89 | elif name == 'testnet': 90 | params = bitcoin.core.coreparams = TestNetParams() 91 | elif name == 'regtest': 92 | params = bitcoin.core.coreparams = RegTestParams() 93 | elif name == 'signet': 94 | params = bitcoin.core.coreparams = SigNetParams() 95 | else: 96 | raise ValueError('Unknown chain %r' % name) 97 | -------------------------------------------------------------------------------- /bitcoin/base58.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 Sam Rushing 2 | # Copyright (C) 2013-2014 The python-bitcoinlib developers 3 | # 4 | # This file is part of python-bitcoinlib. 5 | # 6 | # It is subject to the license terms in the LICENSE file found in the top-level 7 | # directory of this distribution. 8 | # 9 | # No part of python-bitcoinlib, including this file, may be copied, modified, 10 | # propagated, or distributed except according to the terms contained in the 11 | # LICENSE file. 12 | 13 | """Base58 encoding and decoding""" 14 | 15 | 16 | import binascii 17 | 18 | import bitcoin.core 19 | 20 | B58_DIGITS = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 21 | 22 | class Base58Error(Exception): 23 | pass 24 | 25 | class InvalidBase58Error(Base58Error): 26 | """Raised on generic invalid base58 data, such as bad characters. 27 | 28 | Checksum failures raise Base58ChecksumError specifically. 29 | """ 30 | pass 31 | 32 | def encode(b): 33 | """Encode bytes to a base58-encoded string""" 34 | 35 | # Convert big-endian bytes to integer 36 | n = int('0x0' + binascii.hexlify(b).decode('utf8'), 16) 37 | 38 | # Divide that integer into bas58 39 | res = [] 40 | while n > 0: 41 | n, r = divmod(n, 58) 42 | res.append(B58_DIGITS[r]) 43 | res = ''.join(res[::-1]) 44 | 45 | # Encode leading zeros as base58 zeros 46 | czero = 0 47 | pad = 0 48 | for c in b: 49 | if c == czero: 50 | pad += 1 51 | else: 52 | break 53 | return B58_DIGITS[0] * pad + res 54 | 55 | def decode(s): 56 | """Decode a base58-encoding string, returning bytes""" 57 | if not s: 58 | return b'' 59 | 60 | # Convert the string to an integer 61 | n = 0 62 | for c in s: 63 | n *= 58 64 | if c not in B58_DIGITS: 65 | raise InvalidBase58Error('Character %r is not a valid base58 character' % c) 66 | digit = B58_DIGITS.index(c) 67 | n += digit 68 | 69 | # Convert the integer to bytes 70 | h = '%x' % n 71 | if len(h) % 2: 72 | h = '0' + h 73 | res = binascii.unhexlify(h.encode('utf8')) 74 | 75 | # Add padding back. 76 | pad = 0 77 | for c in s[:-1]: 78 | if c == B58_DIGITS[0]: pad += 1 79 | else: break 80 | return b'\x00' * pad + res 81 | 82 | 83 | class Base58ChecksumError(Base58Error): 84 | """Raised on Base58 checksum errors""" 85 | pass 86 | 87 | class CBase58Data(bytes): 88 | """Base58-encoded data 89 | 90 | Includes a version and checksum. 91 | """ 92 | def __new__(cls, s): 93 | k = decode(s) 94 | verbyte, data, check0 = k[0:1], k[1:-4], k[-4:] 95 | check1 = bitcoin.core.Hash(verbyte + data)[:4] 96 | if check0 != check1: 97 | raise Base58ChecksumError('Checksum mismatch: expected %r, calculated %r' % (check0, check1)) 98 | 99 | return cls.from_bytes(data, verbyte[0]) 100 | 101 | def __init__(self, s): 102 | """Initialize from base58-encoded string 103 | 104 | Note: subclasses put your initialization routines here, but ignore the 105 | argument - that's handled by __new__(), and .from_bytes() will call 106 | __init__() with None in place of the string. 107 | """ 108 | 109 | @classmethod 110 | def from_bytes(cls, data, nVersion): 111 | """Instantiate from data and nVersion""" 112 | if not (0 <= nVersion <= 255): 113 | raise ValueError('nVersion must be in range 0 to 255 inclusive; got %d' % nVersion) 114 | self = bytes.__new__(cls, data) 115 | self.nVersion = nVersion 116 | 117 | return self 118 | 119 | def to_bytes(self): 120 | """Convert to bytes instance 121 | 122 | Note that it's the data represented that is converted; the checkum and 123 | nVersion is not included. 124 | """ 125 | return b'' + self 126 | 127 | def __str__(self): 128 | """Convert to string""" 129 | vs = bytes([self.nVersion]) + self 130 | check = bitcoin.core.Hash(vs)[0:4] 131 | return encode(vs + check) 132 | 133 | def __repr__(self): 134 | return '%s(%r)' % (self.__class__.__name__, str(self)) 135 | 136 | __all__ = ( 137 | 'B58_DIGITS', 138 | 'Base58Error', 139 | 'InvalidBase58Error', 140 | 'encode', 141 | 'decode', 142 | 'Base58ChecksumError', 143 | 'CBase58Data', 144 | ) 145 | -------------------------------------------------------------------------------- /bitcoin/bech32.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | """Bech32 encoding and decoding""" 13 | 14 | from bitcoin.segwit_addr import encode, decode 15 | import bitcoin 16 | 17 | class Bech32Error(Exception): 18 | pass 19 | 20 | class Bech32ChecksumError(Bech32Error): 21 | pass 22 | 23 | class CBech32Data(bytes): 24 | """Bech32-encoded data 25 | 26 | Includes a witver and checksum. 27 | """ 28 | def __new__(cls, s): 29 | """from bech32 addr to """ 30 | witver, data = decode(bitcoin.params.BECH32_HRP, s) 31 | if witver is None and data is None: 32 | raise Bech32Error('Bech32 decoding error') 33 | 34 | return cls.from_bytes(witver, data) 35 | 36 | def __init__(self, s): 37 | """Initialize from bech32-encoded string 38 | 39 | Note: subclasses put your initialization routines here, but ignore the 40 | argument - that's handled by __new__(), and .from_bytes() will call 41 | __init__() with None in place of the string. 42 | """ 43 | 44 | @classmethod 45 | def from_bytes(cls, witver, witprog): 46 | """Instantiate from witver and data""" 47 | if not (0 <= witver <= 16): 48 | raise ValueError('witver must be in range 0 to 16 inclusive; got %d' % witver) 49 | self = bytes.__new__(cls, witprog) 50 | self.witver = witver 51 | 52 | return self 53 | 54 | def to_bytes(self): 55 | """Convert to bytes instance 56 | 57 | Note that it's the data represented that is converted; the checkum and 58 | witver is not included. 59 | """ 60 | return b'' + self 61 | 62 | def __str__(self): 63 | """Convert to string""" 64 | return encode(bitcoin.params.BECH32_HRP, self.witver, self) 65 | 66 | def __repr__(self): 67 | return '%s(%r)' % (self.__class__.__name__, str(self)) 68 | 69 | __all__ = ( 70 | 'Bech32Error', 71 | 'Bech32ChecksumError', 72 | 'CBech32Data', 73 | ) 74 | -------------------------------------------------------------------------------- /bitcoin/bloom.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | """Bloom filter support""" 13 | 14 | 15 | import struct 16 | import math 17 | 18 | import bitcoin.core 19 | import bitcoin.core.serialize 20 | 21 | def _ROTL32(x, r): 22 | assert x <= 0xFFFFFFFF 23 | return ((x << r) & 0xFFFFFFFF) | (x >> (32 - r)) 24 | 25 | def MurmurHash3(nHashSeed, vDataToHash): 26 | """MurmurHash3 (x86_32) 27 | 28 | Used for bloom filters. See http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp 29 | """ 30 | 31 | assert nHashSeed <= 0xFFFFFFFF 32 | 33 | h1 = nHashSeed 34 | c1 = 0xcc9e2d51 35 | c2 = 0x1b873593 36 | 37 | # body 38 | i = 0 39 | while (i < len(vDataToHash) - len(vDataToHash) % 4 40 | and len(vDataToHash) - i >= 4): 41 | 42 | k1 = struct.unpack(b"= 3: 58 | k1 ^= vDataToHash[j+2] << 16 59 | if len(vDataToHash) & 3 >= 2: 60 | k1 ^= vDataToHash[j+1] << 8 61 | if len(vDataToHash) & 3 >= 1: 62 | k1 ^= vDataToHash[j] 63 | 64 | k1 &= 0xFFFFFFFF 65 | k1 = (k1 * c1) & 0xFFFFFFFF 66 | k1 = _ROTL32(k1, 15) 67 | k1 = (k1 * c2) & 0xFFFFFFFF 68 | h1 ^= k1 69 | 70 | # finalization 71 | h1 ^= len(vDataToHash) & 0xFFFFFFFF 72 | h1 ^= (h1 & 0xFFFFFFFF) >> 16 73 | h1 *= 0x85ebca6b 74 | h1 ^= (h1 & 0xFFFFFFFF) >> 13 75 | h1 *= 0xc2b2ae35 76 | h1 ^= (h1 & 0xFFFFFFFF) >> 16 77 | 78 | return h1 & 0xFFFFFFFF 79 | 80 | 81 | class CBloomFilter(bitcoin.core.serialize.Serializable): 82 | # 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001% 83 | MAX_BLOOM_FILTER_SIZE = 36000 84 | MAX_HASH_FUNCS = 50 85 | 86 | UPDATE_NONE = 0 87 | UPDATE_ALL = 1 88 | UPDATE_P2PUBKEY_ONLY = 2 89 | UPDATE_MASK = 3 90 | 91 | def __init__(self, nElements, nFPRate, nTweak, nFlags): 92 | """Create a new bloom filter 93 | 94 | The filter will have a given false-positive rate when filled with the 95 | given number of elements. 96 | 97 | Note that if the given parameters will result in a filter outside the 98 | bounds of the protocol limits, the filter created will be as close to 99 | the given parameters as possible within the protocol limits. This will 100 | apply if nFPRate is very low or nElements is unreasonably high. 101 | 102 | nTweak is a constant which is added to the seed value passed to the 103 | hash function It should generally always be a random value (and is 104 | largely only exposed for unit testing) 105 | 106 | nFlags should be one of the UPDATE_* enums (but not _MASK) 107 | """ 108 | LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455 109 | LN2 = 0.6931471805599453094172321214581765680755001343602552 110 | self.vData = bytearray(int(min(-1 / LN2SQUARED * nElements * math.log(nFPRate), self.MAX_BLOOM_FILTER_SIZE * 8) / 8)) 111 | self.nHashFuncs = int(min(len(self.vData) * 8 / nElements * LN2, self.MAX_HASH_FUNCS)) 112 | self.nTweak = nTweak 113 | self.nFlags = nFlags 114 | 115 | def bloom_hash(self, nHashNum, vDataToHash): 116 | return MurmurHash3(((nHashNum * 0xFBA4C795) + self.nTweak) & 0xFFFFFFFF, vDataToHash) % (len(self.vData) * 8) 117 | 118 | __bit_mask = bytearray([0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]) 119 | 120 | def insert(self, elem): 121 | """Insert an element in the filter. 122 | 123 | elem may be a COutPoint or bytes 124 | """ 125 | if isinstance(elem, bitcoin.core.COutPoint): 126 | elem = elem.serialize() 127 | 128 | if len(self.vData) == 1 and self.vData[0] == 0xff: 129 | return 130 | 131 | for i in range(0, self.nHashFuncs): 132 | nIndex = self.bloom_hash(i, elem) 133 | # Sets bit nIndex of vData 134 | self.vData[nIndex >> 3] |= self.__bit_mask[7 & nIndex] 135 | 136 | def contains(self, elem): 137 | """Test if the filter contains an element 138 | 139 | elem may be a COutPoint or bytes 140 | """ 141 | if isinstance(elem, bitcoin.core.COutPoint): 142 | elem = elem.serialize() 143 | 144 | if len(self.vData) == 1 and self.vData[0] == 0xff: 145 | return True 146 | 147 | for i in range(0, self.nHashFuncs): 148 | nIndex = self.bloom_hash(i, elem) 149 | if not (self.vData[nIndex >> 3] & self.__bit_mask[7 & nIndex]): 150 | return False 151 | return True 152 | 153 | def IsWithinSizeConstraints(self): 154 | return len(self.vData) <= self.MAX_BLOOM_FILTER_SIZE and self.nHashFuncs <= self.MAX_HASH_FUNCS 155 | 156 | def IsRelevantAndUpdate(tx, tx_hash): 157 | # Not useful for a client, so not implemented yet. 158 | raise NotImplementedError 159 | 160 | __struct = struct.Struct(b' 0: 32 | s.append((v >> ((i - 1) * 8)) & 0xff) 33 | i -= 1 34 | return s 35 | 36 | def bin2bn(s): 37 | l = 0 38 | for ch in s: 39 | l = (l << 8) | ch 40 | return l 41 | 42 | def bn2mpi(v): 43 | have_ext = False 44 | if v.bit_length() > 0: 45 | have_ext = (v.bit_length() & 0x07) == 0 46 | 47 | neg = False 48 | if v < 0: 49 | neg = True 50 | v = -v 51 | 52 | s = struct.pack(b">I", bn_bytes(v, have_ext)) 53 | ext = bytearray() 54 | if have_ext: 55 | ext.append(0) 56 | v_bin = bn2bin(v) 57 | if neg: 58 | if have_ext: 59 | ext[0] |= 0x80 60 | else: 61 | v_bin[0] |= 0x80 62 | return s + ext + v_bin 63 | 64 | def mpi2bn(s): 65 | if len(s) < 4: 66 | return None 67 | s_size = bytes(s[:4]) 68 | v_len = struct.unpack(b">I", s_size)[0] 69 | if len(s) != (v_len + 4): 70 | return None 71 | if v_len == 0: 72 | return 0 73 | 74 | v_str = bytearray(s[4:]) 75 | neg = False 76 | i = v_str[0] 77 | if i & 0x80: 78 | neg = True 79 | i &= ~0x80 80 | v_str[0] = i 81 | 82 | v = bin2bn(v_str) 83 | 84 | if neg: 85 | return -v 86 | return v 87 | 88 | # bitcoin-specific little endian format, with implicit size 89 | def mpi2vch(s): 90 | r = s[4:] # strip size 91 | r = r[::-1] # reverse string, converting BE->LE 92 | return r 93 | 94 | def bn2vch(v): 95 | return bytes(mpi2vch(bn2mpi(v))) 96 | 97 | def vch2mpi(s): 98 | r = struct.pack(b">I", len(s)) # size 99 | r += s[::-1] # reverse string, converting LE->BE 100 | return r 101 | 102 | def vch2bn(s): 103 | return mpi2bn(vch2mpi(s)) 104 | 105 | -------------------------------------------------------------------------------- /bitcoin/core/contrib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petertodd/python-bitcoinlib/91e334d831fd16c60c932ad7df42c88fd6567c02/bitcoin/core/contrib/__init__.py -------------------------------------------------------------------------------- /bitcoin/core/contrib/ripemd160.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 Pieter Wuille 2 | # Distributed under the MIT software license, see the accompanying 3 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | """ 5 | Pure Python RIPEMD160 implementation. Note that this impelentation is not constant time. 6 | Original source: https://github.com/bitcoin/bitcoin/pull/23716 7 | """ 8 | 9 | # Message schedule indexes for the left path. 10 | ML = [ 11 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 12 | 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 13 | 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 14 | 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 15 | 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 16 | ] 17 | 18 | # Message schedule indexes for the right path. 19 | MR = [ 20 | 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 21 | 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 22 | 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 23 | 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 24 | 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 25 | ] 26 | 27 | # Rotation counts for the left path. 28 | RL = [ 29 | 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 30 | 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 31 | 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 32 | 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 33 | 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 34 | ] 35 | 36 | # Rotation counts for the right path. 37 | RR = [ 38 | 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 39 | 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 40 | 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 41 | 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 42 | 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 43 | ] 44 | 45 | # K constants for the left path. 46 | KL = [0, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e] 47 | 48 | # K constants for the right path. 49 | KR = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0] 50 | 51 | 52 | def fi(x, y, z, i): 53 | """The f1, f2, f3, f4, and f5 functions from the specification.""" 54 | if i == 0: 55 | return x ^ y ^ z 56 | elif i == 1: 57 | return (x & y) | (~x & z) 58 | elif i == 2: 59 | return (x | ~y) ^ z 60 | elif i == 3: 61 | return (x & z) | (y & ~z) 62 | elif i == 4: 63 | return x ^ (y | ~z) 64 | else: 65 | assert False 66 | 67 | 68 | def rol(x, i): 69 | """Rotate the bottom 32 bits of x left by i bits.""" 70 | return ((x << i) | ((x & 0xffffffff) >> (32 - i))) & 0xffffffff 71 | 72 | 73 | def compress(h0, h1, h2, h3, h4, block): 74 | """Compress state (h0, h1, h2, h3, h4) with block.""" 75 | # Left path variables. 76 | al, bl, cl, dl, el = h0, h1, h2, h3, h4 77 | # Right path variables. 78 | ar, br, cr, dr, er = h0, h1, h2, h3, h4 79 | # Message variables. 80 | x = [int.from_bytes(block[4*i:4*(i+1)], 'little') for i in range(16)] 81 | 82 | # Iterate over the 80 rounds of the compression. 83 | for j in range(80): 84 | rnd = j >> 4 85 | # Perform left side of the transformation. 86 | al = rol(al + fi(bl, cl, dl, rnd) + x[ML[j]] + KL[rnd], RL[j]) + el 87 | al, bl, cl, dl, el = el, al, bl, rol(cl, 10), dl 88 | # Perform right side of the transformation. 89 | ar = rol(ar + fi(br, cr, dr, 4 - rnd) + x[MR[j]] + KR[rnd], RR[j]) + er 90 | ar, br, cr, dr, er = er, ar, br, rol(cr, 10), dr 91 | 92 | # Compose old state, left transform, and right transform into new state. 93 | return h1 + cl + dr, h2 + dl + er, h3 + el + ar, h4 + al + br, h0 + bl + cr 94 | 95 | 96 | def ripemd160(data): 97 | """Compute the RIPEMD-160 hash of data.""" 98 | # Initialize state. 99 | state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0) 100 | # Process full 64-byte blocks in the input. 101 | for b in range(len(data) >> 6): 102 | state = compress(*state, data[64*b:64*(b+1)]) 103 | # Construct final blocks (with padding and size). 104 | pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63) 105 | fin = data[len(data) & ~63:] + pad + (8 * len(data)).to_bytes(8, 'little') 106 | # Process final blocks. 107 | for b in range(len(fin) >> 6): 108 | state = compress(*state, fin[64*b:64*(b+1)]) 109 | # Produce output. 110 | return b"".join((h & 0xffffffff).to_bytes(4, 'little') for h in state) -------------------------------------------------------------------------------- /bitcoin/core/serialize.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | """Serialization routines 13 | 14 | You probably don't need to use these directly. 15 | """ 16 | 17 | 18 | import hashlib 19 | import struct 20 | 21 | from io import BytesIO 22 | 23 | from bitcoin.core.contrib.ripemd160 import ripemd160 24 | 25 | MAX_SIZE = 0x02000000 26 | 27 | 28 | def Hash(msg): 29 | """SHA256^2(msg) -> bytes""" 30 | return hashlib.sha256(hashlib.sha256(msg).digest()).digest() 31 | 32 | def Hash160(msg): 33 | """RIPEME160(SHA256(msg)) -> bytes""" 34 | return ripemd160(hashlib.sha256(msg).digest()) 35 | 36 | class SerializationError(Exception): 37 | """Base class for serialization errors""" 38 | 39 | 40 | class SerializationTruncationError(SerializationError): 41 | """Serialized data was truncated 42 | 43 | Thrown by deserialize() and stream_deserialize() 44 | """ 45 | 46 | class DeserializationExtraDataError(SerializationError): 47 | """Deserialized data had extra data at the end 48 | 49 | Thrown by deserialize() when not all data is consumed during 50 | deserialization. The deserialized object and extra padding not consumed are 51 | saved. 52 | """ 53 | def __init__(self, msg, obj, padding): 54 | super(DeserializationExtraDataError, self).__init__(msg) 55 | self.obj = obj 56 | self.padding = padding 57 | 58 | def ser_read(f, n): 59 | """Read from a stream safely 60 | 61 | Raises SerializationError and SerializationTruncationError appropriately. 62 | Use this instead of f.read() in your classes stream_(de)serialization() 63 | functions. 64 | """ 65 | if n > MAX_SIZE: 66 | raise SerializationError('Asked to read 0x%x bytes; MAX_SIZE exceeded' % n) 67 | r = f.read(n) 68 | if len(r) < n: 69 | raise SerializationTruncationError('Asked to read %i bytes, but only got %i' % (n, len(r))) 70 | return r 71 | 72 | 73 | class Serializable(object): 74 | """Base class for serializable objects""" 75 | 76 | __slots__ = [] 77 | 78 | def stream_serialize(self, f, **kwargs): 79 | """Serialize to a stream""" 80 | raise NotImplementedError 81 | 82 | @classmethod 83 | def stream_deserialize(cls, f, **kwargs): 84 | """Deserialize from a stream""" 85 | raise NotImplementedError 86 | 87 | def serialize(self, params={}): 88 | """Serialize, returning bytes""" 89 | f = BytesIO() 90 | self.stream_serialize(f, **params) 91 | return f.getvalue() 92 | 93 | @classmethod 94 | def deserialize(cls, buf, allow_padding=False, params={}): 95 | """Deserialize bytes, returning an instance 96 | 97 | allow_padding - Allow buf to include extra padding. (default False) 98 | 99 | If allow_padding is False and not all bytes are consumed during 100 | deserialization DeserializationExtraDataError will be raised. 101 | """ 102 | fd = BytesIO(buf) 103 | r = cls.stream_deserialize(fd, **params) 104 | if not allow_padding: 105 | padding = fd.read() 106 | if len(padding) != 0: 107 | raise DeserializationExtraDataError('Not all bytes consumed during deserialization', 108 | r, padding) 109 | return r 110 | 111 | def GetHash(self): 112 | """Return the hash of the serialized object""" 113 | return Hash(self.serialize()) 114 | 115 | def __eq__(self, other): 116 | if (not isinstance(other, self.__class__) and 117 | not isinstance(self, other.__class__)): 118 | return NotImplemented 119 | return self.serialize() == other.serialize() 120 | 121 | def __ne__(self, other): 122 | return not (self == other) 123 | 124 | def __hash__(self): 125 | return hash(self.serialize()) 126 | 127 | class ImmutableSerializable(Serializable): 128 | """Immutable serializable object""" 129 | 130 | __slots__ = ['_cached_GetHash', '_cached__hash__'] 131 | 132 | def __setattr__(self, name, value): 133 | raise AttributeError('Object is immutable') 134 | 135 | def __delattr__(self, name): 136 | raise AttributeError('Object is immutable') 137 | 138 | def GetHash(self): 139 | """Return the hash of the serialized object""" 140 | try: 141 | return self._cached_GetHash 142 | except AttributeError: 143 | _cached_GetHash = super(ImmutableSerializable, self).GetHash() 144 | object.__setattr__(self, '_cached_GetHash', _cached_GetHash) 145 | return _cached_GetHash 146 | 147 | def __hash__(self): 148 | try: 149 | return self._cached__hash__ 150 | except AttributeError: 151 | _cached__hash__ = hash(self.serialize()) 152 | object.__setattr__(self, '_cached__hash__', _cached__hash__) 153 | return _cached__hash__ 154 | 155 | class Serializer(object): 156 | """Base class for object serializers""" 157 | def __new__(cls): 158 | raise NotImplementedError 159 | 160 | @classmethod 161 | def stream_serialize(cls, obj, f): 162 | raise NotImplementedError 163 | 164 | @classmethod 165 | def stream_deserialize(cls, f): 166 | raise NotImplementedError 167 | 168 | @classmethod 169 | def serialize(cls, obj): 170 | f = BytesIO() 171 | cls.stream_serialize(obj, f) 172 | return f.getvalue() 173 | 174 | @classmethod 175 | def deserialize(cls, buf): 176 | if isinstance(buf, str) or isinstance(buf, bytes): 177 | buf = BytesIO(buf) 178 | return cls.stream_deserialize(buf) 179 | 180 | 181 | class VarIntSerializer(Serializer): 182 | """Serialization of variable length ints""" 183 | @classmethod 184 | def stream_serialize(cls, i, f): 185 | if i < 0: 186 | raise ValueError('varint must be non-negative integer') 187 | elif i < 0xfd: 188 | f.write(bytes([i])) 189 | elif i <= 0xffff: 190 | f.write(b'\xfd') 191 | f.write(struct.pack(b'> 24) & 0xFF 312 | if nbytes <= 3: 313 | v = (c & 0xFFFFFF) >> 8 * (3 - nbytes) 314 | else: 315 | v = (c & 0xFFFFFF) << (8 * (nbytes - 3)) 316 | return v 317 | 318 | def compact_from_uint256(v): 319 | """Convert uint256 to compact encoding 320 | """ 321 | nbytes = (v.bit_length() + 7) >> 3 322 | compact = 0 323 | if nbytes <= 3: 324 | compact = (v & 0xFFFFFF) << 8 * (3 - nbytes) 325 | else: 326 | compact = v >> 8 * (nbytes - 3) 327 | compact = compact & 0xFFFFFF 328 | 329 | # If the sign bit (0x00800000) is set, divide the mantissa by 256 and 330 | # increase the exponent to get an encoding without it set. 331 | if compact & 0x00800000: 332 | compact >>= 8 333 | nbytes += 1 334 | 335 | return compact | nbytes << 24 336 | 337 | def uint256_to_str(u): 338 | r = b"" 339 | for i in range(8): 340 | r += struct.pack('> (i * 32) & 0xffffffff) 341 | return r 342 | 343 | def uint256_to_shortstr(u): 344 | s = "%064x" % (u,) 345 | return s[:16] 346 | 347 | __all__ = ( 348 | 'MAX_SIZE', 349 | 'Hash', 350 | 'Hash160', 351 | 'SerializationError', 352 | 'SerializationTruncationError', 353 | 'DeserializationExtraDataError', 354 | 'ser_read', 355 | 'Serializable', 356 | 'ImmutableSerializable', 357 | 'Serializer', 358 | 'VarIntSerializer', 359 | 'BytesSerializer', 360 | 'VectorSerializer', 361 | 'uint256VectorSerializer', 362 | 'intVectorSerializer', 363 | 'VarStringSerializer', 364 | 'uint256_from_str', 365 | 'uint256_from_compact', 366 | 'compact_from_uint256', 367 | 'uint256_to_str', 368 | 'uint256_to_shortstr', 369 | ) 370 | -------------------------------------------------------------------------------- /bitcoin/net.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import struct 14 | import socket 15 | 16 | from bitcoin.core.serialize import ( 17 | Serializable, 18 | VarStringSerializer, 19 | intVectorSerializer, 20 | ser_read, 21 | uint256VectorSerializer, 22 | ) 23 | from bitcoin.core import b2lx 24 | 25 | PROTO_VERSION = 60002 26 | CADDR_TIME_VERSION = 31402 27 | IPV4_COMPAT = b"\x00" * 10 + b"\xff" * 2 28 | 29 | 30 | class CAddress(Serializable): 31 | def __init__(self, protover=PROTO_VERSION): 32 | self.protover = protover 33 | self.nTime = 0 34 | self.nServices = 1 35 | self.pchReserved = IPV4_COMPAT 36 | self.ip = "0.0.0.0" 37 | self.port = 0 38 | 39 | @classmethod 40 | def stream_deserialize(cls, f, without_time=False): 41 | c = cls() 42 | if c.protover >= CADDR_TIME_VERSION and not without_time: 43 | c.nTime = struct.unpack(b"H", ser_read(f, 2))[0] 54 | return c 55 | 56 | def stream_serialize(self, f, without_time=False): 57 | if self.protover >= CADDR_TIME_VERSION and not without_time: 58 | f.write(struct.pack(b"H", self.port)) 68 | 69 | def __repr__(self): 70 | return "CAddress(nTime=%d nServices=%i ip=%s port=%i)" % (self.nTime, self.nServices, self.ip, self.port) 71 | 72 | 73 | class CInv(Serializable): 74 | typemap = { 75 | 0: "Error", 76 | 1: "TX", 77 | 2: "Block", 78 | 3: "FilteredBlock", 79 | 4: "CompactBlock"} 80 | 81 | def __init__(self): 82 | self.type = 0 83 | self.hash = 0 84 | 85 | @classmethod 86 | def stream_deserialize(cls, f): 87 | c = cls() 88 | c.type = struct.unpack(b"> 25 32 | chk = (chk & 0x1ffffff) << 5 ^ value 33 | for i in range(5): 34 | chk ^= generator[i] if ((top >> i) & 1) else 0 35 | return chk 36 | 37 | 38 | def bech32_hrp_expand(hrp): 39 | """Expand the HRP into values for checksum computation.""" 40 | return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] 41 | 42 | 43 | def bech32_verify_checksum(hrp, data): 44 | """Verify a checksum given HRP and converted data characters.""" 45 | return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1 46 | 47 | 48 | def bech32_create_checksum(hrp, data): 49 | """Compute the checksum values given HRP and data.""" 50 | values = bech32_hrp_expand(hrp) + data 51 | polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1 52 | return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] 53 | 54 | 55 | def bech32_encode(hrp, data): 56 | """Compute a Bech32 string given HRP and data values.""" 57 | combined = data + bech32_create_checksum(hrp, data) 58 | return hrp + '1' + ''.join([CHARSET[d] for d in combined]) 59 | 60 | 61 | def bech32_decode(bech): 62 | """Validate a Bech32 string, and determine HRP and data.""" 63 | if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or 64 | (bech.lower() != bech and bech.upper() != bech)): 65 | return (None, None) 66 | bech = bech.lower() 67 | pos = bech.rfind('1') 68 | if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: 69 | return (None, None) 70 | if not all(x in CHARSET for x in bech[pos+1:]): 71 | return (None, None) 72 | hrp = bech[:pos] 73 | data = [CHARSET.find(x) for x in bech[pos+1:]] 74 | if not bech32_verify_checksum(hrp, data): 75 | return (None, None) 76 | return (hrp, data[:-6]) 77 | 78 | 79 | def convertbits(data, frombits, tobits, pad=True): 80 | """General power-of-2 base conversion.""" 81 | acc = 0 82 | bits = 0 83 | ret = [] 84 | maxv = (1 << tobits) - 1 85 | max_acc = (1 << (frombits + tobits - 1)) - 1 86 | for value in data: 87 | if value < 0 or (value >> frombits): 88 | return None 89 | acc = ((acc << frombits) | value) & max_acc 90 | bits += frombits 91 | while bits >= tobits: 92 | bits -= tobits 93 | ret.append((acc >> bits) & maxv) 94 | if pad: 95 | if bits: 96 | ret.append((acc << (tobits - bits)) & maxv) 97 | elif bits >= frombits or ((acc << (tobits - bits)) & maxv): 98 | return None 99 | return ret 100 | 101 | 102 | def decode(hrp, addr): 103 | """Decode a segwit address.""" 104 | hrpgot, data = bech32_decode(addr) 105 | if hrpgot != hrp: 106 | return (None, None) 107 | decoded = convertbits(data[1:], 5, 8, False) 108 | if decoded is None or len(decoded) < 2 or len(decoded) > 40: 109 | return (None, None) 110 | if data[0] > 16: 111 | return (None, None) 112 | if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32: 113 | return (None, None) 114 | return (data[0], decoded) 115 | 116 | 117 | def encode(hrp, witver, witprog): 118 | """Encode a segwit address.""" 119 | ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5)) 120 | if decode(hrp, ret) == (None, None): 121 | return None 122 | return ret 123 | -------------------------------------------------------------------------------- /bitcoin/signature.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | from bitcoin.core.serialize import * 14 | 15 | # Py3 compatibility 16 | import sys 17 | 18 | from io import BytesIO 19 | 20 | 21 | class DERSignature(ImmutableSerializable): 22 | __slots__ = ['length', 'r', 's'] 23 | 24 | def __init__(self, r, s, length): 25 | object.__setattr__(self, 'r', r) 26 | object.__setattr__(self, 's', s) 27 | object.__setattr__(self, 'length', length) 28 | 29 | @classmethod 30 | def stream_deserialize(cls, f): 31 | assert ser_read(f, 1) == b"\x30" 32 | rs = BytesSerializer.stream_deserialize(f) 33 | f = BytesIO(rs) 34 | assert ser_read(f, 1) == b"\x02" 35 | r = BytesSerializer.stream_deserialize(f) 36 | assert ser_read(f, 1) == b"\x02" 37 | s = BytesSerializer.stream_deserialize(f) 38 | return cls(r, s, len(r + s)) 39 | 40 | def stream_serialize(self, f): 41 | f.write(b"\x30") 42 | f.write(b"\x02") 43 | BytesSerializer.stream_serialize(self.r, f) 44 | f.write(b"\x30") 45 | BytesSerializer.stream_serialize(self.s, f) 46 | 47 | def __repr__(self): 48 | return 'DERSignature(%s, %s)' % (self.r, self.s) 49 | 50 | 51 | __all__ = ( 52 | 'DERSignature', 53 | ) 54 | -------------------------------------------------------------------------------- /bitcoin/signmessage.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | from bitcoin.core.key import CPubKey 14 | from bitcoin.core.serialize import ImmutableSerializable 15 | from bitcoin.wallet import P2PKHBitcoinAddress 16 | import bitcoin 17 | import base64 18 | 19 | 20 | def VerifyMessage(address, message, sig): 21 | sig = base64.b64decode(sig) 22 | hash = message.GetHash() 23 | 24 | pubkey = CPubKey.recover_compact(hash, sig) 25 | 26 | return str(P2PKHBitcoinAddress.from_pubkey(pubkey)) == str(address) 27 | 28 | 29 | def SignMessage(key, message): 30 | sig, i = key.sign_compact(message.GetHash()) 31 | 32 | meta = 27 + i 33 | if key.is_compressed: 34 | meta += 4 35 | 36 | return base64.b64encode(bytes([meta]) + sig) 37 | 38 | 39 | class BitcoinMessage(ImmutableSerializable): 40 | __slots__ = ['magic', 'message'] 41 | 42 | def __init__(self, message="", magic="Bitcoin Signed Message:\n"): 43 | object.__setattr__(self, 'message', message.encode("utf-8")) 44 | object.__setattr__(self, 'magic', magic.encode("utf-8")) 45 | 46 | @classmethod 47 | def stream_deserialize(cls, f): 48 | magic = bitcoin.core.serialize.BytesSerializer.stream_deserialize(f) 49 | message = bitcoin.core.serialize.BytesSerializer.stream_deserialize(f) 50 | return cls(message, magic) 51 | 52 | def stream_serialize(self, f): 53 | bitcoin.core.serialize.BytesSerializer.stream_serialize(self.magic, f) 54 | bitcoin.core.serialize.BytesSerializer.stream_serialize(self.message, f) 55 | 56 | def __str__(self): 57 | return self.message.decode('ascii') 58 | 59 | def __repr__(self): 60 | return 'BitcoinMessage(%s, %s)' % (self.magic, self.message) 61 | -------------------------------------------------------------------------------- /bitcoin/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | -------------------------------------------------------------------------------- /bitcoin/tests/data/base58_encode_decode.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["", ""], 3 | ["61", "2g"], 4 | ["626262", "a3gV"], 5 | ["636363", "aPEr"], 6 | ["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"], 7 | ["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"], 8 | ["516b6fcd0f", "ABnLTmg"], 9 | ["bf4f89001e670274dd", "3SEo3LWLoPntC"], 10 | ["572e4794", "3EFU7m"], 11 | ["ecac89cad93923c02321", "EJDM8drfXA6uyA"], 12 | ["10c8511e", "Rt5zm"], 13 | ["00000000000000000000", "1111111111"] 14 | ] 15 | -------------------------------------------------------------------------------- /bitcoin/tests/data/bech32_encode_decode.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["0014751e76e8199196d454941c45d1b3a323f1433bd6", "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4"], 3 | ["00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262", "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7"], 4 | ["5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6", "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx"], 5 | ["6002751e", "BC1SW50QA3JX3S"], 6 | ["5210751e76e8199196d454941c45d1b3a323", "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj"], 7 | ["0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy"] 8 | ] 9 | -------------------------------------------------------------------------------- /bitcoin/tests/data/bech32_invalid.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", "Invalid human-readable part"], 3 | ["bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", "Invalid checksum"], 4 | ["BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", "Invalid witness version"], 5 | ["bc1rw5uspcuh", "Invalid program length"], 6 | ["bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", "Invalid program length"], 7 | ["BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", "Invalid program length for witness version 0 (per BIP141)"], 8 | ["tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", "Mixed case"], 9 | ["bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", "zero padding of more than 4 bits"], 10 | ["tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", "Non-zero padding in 8-to-5 conversion"], 11 | ["bc1gmk9yu", "Empty data section"] 12 | ] -------------------------------------------------------------------------------- /bitcoin/tests/data/checkblock_invalid.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["CheckBlock and CheckBlockHeader tests, valid blocks."], 3 | ["They are in the form"], 4 | ["[comment, fHeader, fCheckPow, cur_time, serialized_block/block_header],"], 5 | ["Objects that are only a single string (like this one) are ignored"], 6 | 7 | ["Genesis block with time set to two hours + 1 second behind", 8 | false, true, 1230999304, 9 | "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"], 10 | 11 | ["Genesis with one byte changed", 12 | false, true, 1231006505, 13 | "1100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"], 14 | 15 | ["Empty vtx", 16 | false, false, 0, 17 | "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a00000000ffff001d1dac2b7c00"], 18 | 19 | ["One tx, but not a coinbase", 20 | false, false, 1231731025, 21 | "0100000055bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f451b96a49ffff001d283e9e70010100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000"], 22 | 23 | ["More than one coinbase (different coinbases)", 24 | false, false, 1231731025, 25 | "0100000055bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000622d1f9da7a372968847d7ecfc3892c51ccc08297762c4a767b51cdd6628d2cf51b96a49ffff001d283e9e700201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0102ffffffff0100f2052a01000000434104d46c4968bde02899d2aa0963367c7a6ce34eec332b32e42e5f3407e052d64ac625da6f0718e7b302140434bd725706957c092db53805b821a85b23a7ac61725bac0000000001000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0102ffffffff0100f2052a01000000434104d46c4968bde02899d2aa0963367c7a6ce34eec332b32e42e5f3407e052d64ac625da6f0718e7b302140434bd725706957c092db53805b821a85b23a7ac61725bac01000000"], 26 | 27 | ["Duplicate transaction", 28 | false, false, 1231731025, 29 | "0100000055bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000ff104ccb05421ab93e63f8c3ce5c2c2e9dbb37de2764b3a3175c8166562cac7d51b96a49ffff001d283e9e700301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0102ffffffff0100f2052a01000000434104d46c4968bde02899d2aa0963367c7a6ce34eec332b32e42e5f3407e052d64ac625da6f0718e7b302140434bd725706957c092db53805b821a85b23a7ac61725bac000000000100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac000000000100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000"], 30 | 31 | ["Merkle root mismatch", 32 | false, false, 1293603080, 33 | "01000000e78b20013e6e9a21b6366ead5d866b2f9dc00664508b90f24da8000000000000f94b61259c7e9af3455b277275800d0d6a58b929eedf9e0153a6ef2278a5d53408d11a4d4c86041b0fbf10b00301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0119ffffffff0100f2052a0100000043410427e729f9cb5564abf2a1ccda596c636b77bd4d9d91f657d4738f3c70fce8ac4e12b1c782905554d9ff2c2e050fdfe3ff93c91c5817e617877d51f450b528c9e4ac000000000100000001e853c9e0c133547fd9e162b1d3860dd0f27d5b9b8a7430d28896c00fbb3f1bc7000000008c49304602210095bcd54ebd0caa7cee75f0f89de472a765e6ef4b98c5fd4b32c7f9d4905db9ae022100ebd3f668e3a1a36d56e30184c27531dbb9fc136c84b1282be562064d86997d1e014104727eb4fdcc90658cd26abe7dcb0ae7297810b15b9e27c32bcf8e3edd934901968806dc18b1276d7273cc4c223feee0070361ed947888a3cef422bebfede96e08ffffffff020065cd1d000000001976a91468c6c2b3c0bc4a8eeb10d16a300d627a31a3b58588ac0008af2f000000001976a9141d87f0a54a1d704ffc70eae83b025698bc0fdcfc88ac00000000010000000125f582f1d37b6713b14b85665a2daea4f464f5ed1c3ab3d4dcf152fb61414b9e000000008a473044022066ec12ced31659e1bf961b542b58bba76ba8f2a1e8f36d5f60be0601598eac21022047ce33685a63283a4c3ebc390261191f215999b2f7d8e1504b8af39aae4a2881014104c5e1d713d10fe59cc48f60701a3efcac418969c22e9c6cf57440f71e44dc82837af5351bf3e1d898f06aa5c792bf0251a39902311d1d27c16847b1b414494f35ffffffff02404b4c00000000001976a91466a3b2e43cfa5c6d9b2f0095f7be5a5cb608478c88ac80b8dc3c030000001976a9146df5ed8cee34df5c05c90406761a11ed143c202d88ac01000000"], 34 | 35 | ["FIXME: need to test sigops count, among other things"], 36 | 37 | ["Make diffs cleaner by leaving a comment here without comma at the end"] 38 | ] 39 | -------------------------------------------------------------------------------- /bitcoin/tests/data/checkblock_valid.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["CheckBlock and CheckBlockHeader tests, valid blocks."], 3 | ["They are in the form"], 4 | ["[comment, fHeader, fCheckPow, cur_time, serialized_block/block_header],"], 5 | ["Objects that are only a single string (like this one) are ignored"], 6 | 7 | ["Genesis block", 8 | false, true, 1231006505, 9 | "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"], 10 | 11 | ["Genesis block with time set to two hours - 1 second behind", 12 | false, true, 1230999305, 13 | "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"], 14 | 15 | ["Block 99960, three transactions", 16 | false, true, 1293603080, 17 | "01000000e78b20013e6e9a21b6366ead5d866b2f9dc00664508b90f24da8000000000000f94b61259c7e9af3455b277275800d0d6a58b929eedf9e0153a6ef2278a5d53408d11a4d4c86041b0fbf10b00301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0119ffffffff0100f2052a0100000043410427e729f9cb5564abf2a1ccda596c636b77bd4d9d91f657d4738f3c70fce8ac4e12b1c782905554d9ff2c2e050fdfe3ff93c91c5817e617877d51f450b528c9e4ac000000000100000001e853c9e0c133547fd9e162b1d3860dd0f27d5b9b8a7430d28896c00fbb3f1bc7000000008c49304602210095bcd54ebd0caa7cee75f0f89de472a765e6ef4b98c5fd4b32c7f9d4905db9ae022100ebd3f668e3a1a36d56e30184c27531dbb9fc136c84b1282be562064d86997d1e014104727eb4fdcc90658cd26abe7dcb0ae7297810b15b9e27c32bcf8e3edd934901968806dc18b1276d7273cc4c223feee0070361ed947888a3cef422bebfede96e08ffffffff020065cd1d000000001976a91468c6c2b3c0bc4a8eeb10d16a300d627a31a3b58588ac0008af2f000000001976a9141d87f0a54a1d704ffc70eae83b025698bc0fdcfc88ac00000000010000000125f582f1d37b6713b14b85665a2daea4f464f5ed1c3ab3d4dcf152fb61414b9e000000008a473044022066ec12ced31659e1bf961b542b58bba76ba8f2a1e8f36d5f60be0601598eac21022047ce33685a63283a4c3ebc390261191f215999b2f7d8e1504b8af39aae4a2881014104c5e1d713d10fe59cc48f60701a3efcac418969c22e9c6cf57440f71e44dc82837af5351bf3e1d898f06aa5c792bf0251a39902311d1d27c16847b1b414494f35ffffffff02404b4c00000000001976a91466a3b2e43cfa5c6d9b2f0095f7be5a5cb608478c88ac80b8dc3c030000001976a9146df5ed8cee34df5c05c90406761a11ed143c202d88ac00000000"], 18 | 19 | ["Block 99993, four transactions", 20 | false, true, 1293622397, 21 | "01000000acda3db591d5c2c63e8c09e7523a5b0581707ef3e3520d6ca180000000000000701179cb9a9e0fe709cc96261b6b943b31362b61dacba94b03f9b71a06cc2eff7d1c1b4d4c86041b75962f880401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0152ffffffff014034152a01000000434104216220ab283b5e2871c332de670d163fb1b7e509fd67db77997c5568e7c25afd988f19cd5cc5aec6430866ec64b5214826b28e0f7a86458073ff933994b47a5cac0000000001000000042a40ae58b06c3a61ae55dbee05cab546e80c508f71f24ef0cdc9749dac91ea5f000000004a49304602210089c685b37903c4aa62d984929afeaca554d1641f9a668398cd228fb54588f06b0221008a5cfbc5b0a38ba78c4f4341e53272b9cd0e377b2fb740106009b8d7fa693f0b01ffffffff7b999491e30af112b11105cb053bc3633a8a87f44740eb158849a76891ff228b00000000494830450221009a4aa8663ff4017063d2020519f2eade5b4e3e30be69bf9a62b4e6472d1747b2022021ee3b3090b8ce439dbf08a5df31e2dc23d68073ebda45dc573e8a4f74f5cdfc01ffffffffdea82ec2f9e88e0241faa676c13d093030b17c479770c6cc83239436a4327d49000000004a493046022100c29d9de71a34707c52578e355fa0fdc2bb69ce0a957e6b591658a02b1e039d69022100f82c8af79c166a822d305f0832fb800786d831aea419069b3aed97a6edf8f02101fffffffff3e7987da9981c2ae099f97a551783e1b21669ba0bf3aca8fe12896add91a11a0000000049483045022100e332c81781b281a3b35cf75a5a204a2be451746dad8147831255291ebac2604d02205f889a2935270d1bf1ef47db773d68c4d5c6a51bb51f082d3e1c491de63c345601ffffffff0100c817a8040000001976a91420420e56079150b50fb0617dce4c374bd61eccea88ac00000000010000000265a7293b2d69ba51d554cd32ac7586f7fbeaeea06835f26e03a2feab6aec375f000000004a493046022100922361eaafe316003087d355dd3c0ef3d9f44edae661c212a28a91e020408008022100c9b9c84d53d82c0ba9208f695c79eb42a453faea4d19706a8440e1d05e6cff7501fffffffff6971f00725d17c1c531088144b45ed795a307a22d51ca377c6f7f93675bb03a000000008b483045022100d060f2b2f4122edac61a25ea06396fe9135affdabc66d350b5ae1813bc6bf3f302205d8363deef2101fc9f3d528a8b3907e9d29c40772e587dcea12838c574cb80f801410449fce4a25c972a43a6bc67456407a0d4ced782d4cf8c0a35a130d5f65f0561e9f35198349a7c0b4ec79a15fead66bd7642f17cc8c40c5df95f15ac7190c76442ffffffff0200f2052a010000001976a914c3f537bc307c7eda43d86b55695e46047b770ea388ac00cf7b05000000001976a91407bef290008c089a60321b21b1df2d7f2202f40388ac0000000001000000014ab7418ecda2b2531eef0145d4644a4c82a7da1edd285d1aab1ec0595ac06b69000000008c493046022100a796490f89e0ef0326e8460edebff9161da19c36e00c7408608135f72ef0e03e0221009e01ef7bc17cddce8dfda1f1a6d3805c51f9ab2f8f2145793d8e85e0dd6e55300141043e6d26812f24a5a9485c9d40b8712215f0c3a37b0334d76b2c24fcafa587ae5258853b6f49ceeb29cd13ebb76aa79099fad84f516bbba47bd170576b121052f1ffffffff0200a24a04000000001976a9143542e17b6229a25d5b76909f9d28dd6ed9295b2088ac003fab01000000001976a9149cea2b6e3e64ad982c99ebba56a882b9e8a816fe88ac00000000"], 22 | 23 | ["FIXME: need test cases for PoW"], 24 | 25 | ["Make diffs cleaner by leaving a comment here without comma at the end"] 26 | ] 27 | -------------------------------------------------------------------------------- /bitcoin/tests/data/tx_invalid.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["The following are deserialized transactions which are invalid."], 3 | ["They are in the form"], 4 | ["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], 5 | ["serializedTransaction, enforceP2SH]"], 6 | ["Objects that are only a single string (like this one) are ignored"], 7 | 8 | ["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"], 9 | [[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]], 10 | "010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", true], 11 | 12 | ["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"], 13 | ["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"], 14 | ["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"], 15 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], 16 | "01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], 17 | 18 | ["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"], 19 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], 20 | "01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", true], 21 | 22 | ["An invalid P2SH Transaction"], 23 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], 24 | "010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", true], 25 | 26 | ["No outputs"], 27 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]], 28 | "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", true], 29 | 30 | ["Negative output"], 31 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]], 32 | "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", true], 33 | 34 | ["MAX_MONEY + 1 output"], 35 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], 36 | "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", true], 37 | 38 | ["MAX_MONEY output + 1 output"], 39 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], 40 | "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", true], 41 | 42 | ["Duplicate inputs"], 43 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]], 44 | "01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", true], 45 | 46 | ["Coinbase of size 1"], 47 | ["Note the input is just required to make the tester happy"], 48 | [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], 49 | "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", true], 50 | 51 | ["Coinbase of size 101"], 52 | ["Note the input is just required to make the tester happy"], 53 | [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], 54 | "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", true], 55 | 56 | ["Null txin"], 57 | [[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], 58 | "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", true], 59 | 60 | ["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], 61 | [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], 62 | ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], 63 | "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", true], 64 | 65 | ["Incorrect signature order"], 66 | ["Note the input is just required to make the tester happy"], 67 | [[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], 68 | "01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", true], 69 | 70 | ["Empty stack when we try to run CHECKSIG"], 71 | [[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]], 72 | "01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", true], 73 | 74 | ["Make diffs cleaner by leaving a comment here without comma at the end"] 75 | ] 76 | -------------------------------------------------------------------------------- /bitcoin/tests/test_base58.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import json 14 | import os 15 | import unittest 16 | 17 | from binascii import unhexlify 18 | 19 | from bitcoin.base58 import * 20 | 21 | 22 | def load_test_vectors(name): 23 | with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: 24 | for testcase in json.load(fd): 25 | yield testcase 26 | 27 | class Test_base58(unittest.TestCase): 28 | def test_encode_decode(self): 29 | for exp_bin, exp_base58 in load_test_vectors('base58_encode_decode.json'): 30 | exp_bin = unhexlify(exp_bin.encode('utf8')) 31 | 32 | act_base58 = encode(exp_bin) 33 | act_bin = decode(exp_base58) 34 | 35 | self.assertEqual(act_base58, exp_base58) 36 | self.assertEqual(act_bin, exp_bin) 37 | 38 | class Test_CBase58Data(unittest.TestCase): 39 | def test_from_data(self): 40 | b = CBase58Data.from_bytes(b"b\xe9\x07\xb1\\\xbf'\xd5BS\x99\xeb\xf6\xf0\xfbP\xeb\xb8\x8f\x18", 0) 41 | self.assertEqual(b.nVersion, 0) 42 | self.assertEqual(str(b), '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa') 43 | 44 | b = CBase58Data.from_bytes(b'Bf\xfco,(a\xd7\xfe"\x9b\'\x9ay\x80:\xfc\xa7\xba4', 196) 45 | self.assertEqual(b.nVersion, 196) 46 | self.assertEqual(str(b), '2MyJKxYR2zNZZsZ39SgkCXWCfQtXKhnWSWq') 47 | 48 | def test_invalid_base58_exception(self): 49 | invalids = ('', # missing everything 50 | '#', # invalid character 51 | '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNb', # invalid checksum 52 | ) 53 | 54 | for invalid in invalids: 55 | msg = '%r should have raised InvalidBase58Error but did not' % invalid 56 | with self.assertRaises(Base58Error, msg=msg): 57 | CBase58Data(invalid) 58 | -------------------------------------------------------------------------------- /bitcoin/tests/test_bech32.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import json 14 | import os 15 | import unittest 16 | from binascii import unhexlify 17 | 18 | from bitcoin.core.script import CScript, OP_0, OP_1, OP_16 19 | from bitcoin.bech32 import * 20 | from bitcoin.segwit_addr import encode, decode 21 | 22 | 23 | def load_test_vectors(name): 24 | with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: 25 | for testcase in json.load(fd): 26 | yield testcase 27 | 28 | def to_scriptPubKey(witver, witprog): 29 | """Decoded bech32 address to script""" 30 | return CScript([witver]) + CScript(bytes(witprog)) 31 | 32 | class Test_bech32(unittest.TestCase): 33 | 34 | def op_decode(self, witver): 35 | """OP encoding to int""" 36 | if witver == OP_0: 37 | return 0 38 | if OP_1 <= witver <= OP_16: 39 | return witver - OP_1 + 1 40 | self.fail('Wrong witver: %d' % witver) 41 | 42 | def test_encode_decode(self): 43 | for exp_bin, exp_bech32 in load_test_vectors('bech32_encode_decode.json'): 44 | exp_bin = unhexlify(exp_bin.encode('utf8')) 45 | witver = self.op_decode(exp_bin[0]) 46 | hrp = exp_bech32[:exp_bech32.rindex('1')].lower() 47 | self.assertEqual(exp_bin[1], len(exp_bin[2:])) 48 | act_bech32 = encode(hrp, witver, exp_bin[2:]) 49 | act_bin = decode(hrp, exp_bech32) 50 | 51 | self.assertEqual(act_bech32.lower(), exp_bech32.lower()) 52 | self.assertEqual(to_scriptPubKey(*act_bin), bytes(exp_bin)) 53 | 54 | class Test_CBech32Data(unittest.TestCase): 55 | def test_from_data(self): 56 | b = CBech32Data.from_bytes(0, unhexlify('751e76e8199196d454941c45d1b3a323f1433bd6')) 57 | self.assertEqual(b.witver, 0) 58 | self.assertEqual(str(b).upper(), 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4') 59 | 60 | def test_invalid_bech32_exception(self): 61 | 62 | for invalid, _ in load_test_vectors("bech32_invalid.json"): 63 | msg = '%r should have raised Bech32Error but did not' % invalid 64 | with self.assertRaises(Bech32Error, msg=msg): 65 | CBech32Data(invalid) 66 | -------------------------------------------------------------------------------- /bitcoin/tests/test_bloom.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import unittest 14 | 15 | import bitcoin.core 16 | from bitcoin.core import x 17 | from bitcoin.bloom import * 18 | 19 | class Test_MurmurHash3(unittest.TestCase): 20 | def test(self): 21 | def T(expected, seed, data): 22 | self.assertEqual(MurmurHash3(seed, x(data)), expected) 23 | 24 | T(0x00000000, 0x00000000, "") 25 | T(0x6a396f08, 0xFBA4C795, "") 26 | T(0x81f16f39, 0xffffffff, "") 27 | 28 | T(0x514e28b7, 0x00000000, "00") 29 | T(0xea3f0b17, 0xFBA4C795, "00") 30 | T(0xfd6cf10d, 0x00000000, "ff") 31 | 32 | T(0x16c6b7ab, 0x00000000, "0011") 33 | T(0x8eb51c3d, 0x00000000, "001122") 34 | T(0xb4471bf8, 0x00000000, "00112233") 35 | T(0xe2301fa8, 0x00000000, "0011223344") 36 | T(0xfc2e4a15, 0x00000000, "001122334455") 37 | T(0xb074502c, 0x00000000, "00112233445566") 38 | T(0x8034d2a0, 0x00000000, "0011223344556677") 39 | T(0xb4698def, 0x00000000, "001122334455667788") 40 | 41 | 42 | class Test_CBloomFilter(unittest.TestCase): 43 | def test_create_insert_serialize(self): 44 | filter = CBloomFilter(3, 0.01, 0, CBloomFilter.UPDATE_ALL) 45 | 46 | def T(elem): 47 | """Filter contains elem""" 48 | elem = x(elem) 49 | filter.insert(elem) 50 | self.assertTrue(filter.contains(elem)) 51 | 52 | def F(elem): 53 | """Filter does not contain elem""" 54 | elem = x(elem) 55 | self.assertFalse(filter.contains(elem)) 56 | 57 | T('99108ad8ed9bb6274d3980bab5a85c048f0950c8') 58 | F('19108ad8ed9bb6274d3980bab5a85c048f0950c8') 59 | T('b5a2c786d9ef4658287ced5914b37a1b4aa32eee') 60 | T('b9300670b4c5366e95b2699e8b18bc75e5f729c5') 61 | 62 | self.assertEqual(filter.serialize(), x('03614e9b050000000000000001')) 63 | deserialized = CBloomFilter.deserialize(x('03614e9b050000000000000001')) 64 | 65 | self.assertTrue(deserialized.contains(x('99108ad8ed9bb6274d3980bab5a85c048f0950c8'))) 66 | self.assertFalse(deserialized.contains(x('19108ad8ed9bb6274d3980bab5a85c048f0950c8'))) 67 | self.assertTrue(deserialized.contains(x('b5a2c786d9ef4658287ced5914b37a1b4aa32eee'))) 68 | self.assertTrue(deserialized.contains(x('b9300670b4c5366e95b2699e8b18bc75e5f729c5'))) 69 | 70 | def test_create_insert_serialize_with_tweak(self): 71 | # Same test as bloom_create_insert_serialize, but we add a nTweak of 100 72 | filter = CBloomFilter(3, 0.01, 2147483649, CBloomFilter.UPDATE_ALL) 73 | 74 | def T(elem): 75 | """Filter contains elem""" 76 | elem = x(elem) 77 | filter.insert(elem) 78 | self.assertTrue(filter.contains(elem)) 79 | 80 | def F(elem): 81 | """Filter does not contain elem""" 82 | elem = x(elem) 83 | self.assertFalse(filter.contains(elem)) 84 | 85 | T('99108ad8ed9bb6274d3980bab5a85c048f0950c8') 86 | F('19108ad8ed9bb6274d3980bab5a85c048f0950c8') 87 | T('b5a2c786d9ef4658287ced5914b37a1b4aa32eee') 88 | T('b9300670b4c5366e95b2699e8b18bc75e5f729c5') 89 | 90 | self.assertEqual(filter.serialize(), x('03ce4299050000000100008001')) 91 | 92 | def test_bloom_create_insert_key(self): 93 | filter = CBloomFilter(2, 0.001, 0, CBloomFilter.UPDATE_ALL) 94 | 95 | pubkey = x('045B81F0017E2091E2EDCD5EECF10D5BDD120A5514CB3EE65B8447EC18BFC4575C6D5BF415E54E03B1067934A0F0BA76B01C6B9AB227142EE1D543764B69D901E0') 96 | pubkeyhash = bitcoin.core.Hash160(pubkey) 97 | 98 | filter.insert(pubkey) 99 | filter.insert(pubkeyhash) 100 | 101 | self.assertEqual(filter.serialize(), x('038fc16b080000000000000001')) 102 | -------------------------------------------------------------------------------- /bitcoin/tests/test_checkblock.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import json 14 | import unittest 15 | import os 16 | 17 | from bitcoin.core import * 18 | 19 | def load_test_vectors(name): 20 | with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: 21 | for test_case in json.load(fd): 22 | # Comments designated by single length strings 23 | if len(test_case) == 1: 24 | continue 25 | assert len(test_case) == 5 26 | 27 | (comment, fHeader, fCheckPoW, cur_time, serialized_blk) = test_case 28 | 29 | blk = None 30 | if fHeader: 31 | blk = CBlockHeader.deserialize(x(serialized_blk)) 32 | else: 33 | blk = CBlock.deserialize(x(serialized_blk)) 34 | 35 | yield (comment, fHeader, fCheckPoW, cur_time, blk) 36 | 37 | 38 | class Test_CheckBlock(unittest.TestCase): 39 | def test_checkblock_valid(self): 40 | for comment, fHeader, fCheckPoW, cur_time, blk in load_test_vectors('checkblock_valid.json'): 41 | try: 42 | if fHeader: 43 | CheckBlockHeader(blk, fCheckPoW=fCheckPoW, cur_time=cur_time) 44 | else: 45 | CheckBlock(blk, fCheckPoW=fCheckPoW, cur_time=cur_time) 46 | except ValidationError as err: 47 | self.fail('Failed "%s" with error %r' % (comment, err)) 48 | 49 | def test_checkblock_invalid(self): 50 | for comment, fHeader, fCheckPoW, cur_time, blk in load_test_vectors('checkblock_invalid.json'): 51 | try: 52 | if fHeader: 53 | CheckBlockHeader(blk, fCheckPoW=fCheckPoW, cur_time=cur_time) 54 | else: 55 | CheckBlock(blk, fCheckPoW=fCheckPoW, cur_time=cur_time) 56 | except ValidationError as err: 57 | continue 58 | 59 | self.fail('Invalid block "%s" passed checks' % comment) 60 | -------------------------------------------------------------------------------- /bitcoin/tests/test_key.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import unittest 14 | 15 | from bitcoin.core.key import * 16 | from bitcoin.core import x 17 | 18 | class Test_CPubKey(unittest.TestCase): 19 | def test(self): 20 | def T(hex_pubkey, is_valid, is_fullyvalid, is_compressed): 21 | key = CPubKey(x(hex_pubkey)) 22 | self.assertEqual(key.is_valid, is_valid) 23 | self.assertEqual(key.is_fullyvalid, is_fullyvalid) 24 | self.assertEqual(key.is_compressed, is_compressed) 25 | 26 | T('', False, False, False) 27 | T('00', True, True, False) # why is this valid? 28 | T('01', True, False, False) 29 | T('02', True, False, False) 30 | 31 | T('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71', 32 | True, True, True) 33 | T('0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71', 34 | True, False, True) 35 | 36 | T('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71', 37 | True, True, True) 38 | 39 | T('0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71a1518063243acd4dfe96b66e3f2ec8013c8e072cd09b3834a19f81f659cc3455', 40 | True, True, False) 41 | -------------------------------------------------------------------------------- /bitcoin/tests/test_messages.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | import unittest 13 | 14 | from bitcoin.messages import msg_version, msg_verack, msg_addr, msg_alert, \ 15 | msg_inv, msg_getdata, msg_getblocks, msg_getheaders, msg_headers, msg_tx, \ 16 | msg_block, msg_getaddr, msg_ping, msg_pong, msg_mempool, MsgSerializable, \ 17 | msg_notfound, msg_reject 18 | 19 | from io import BytesIO 20 | 21 | 22 | class MessageTestCase(unittest.TestCase): 23 | def serialization_test(self, cls): 24 | m = cls() 25 | mSerialized = m.to_bytes() 26 | mDeserialzed = cls.from_bytes(mSerialized) 27 | mSerialzedTwice = mDeserialzed.to_bytes() 28 | self.assertEqual(mSerialized, mSerialzedTwice) 29 | 30 | 31 | class Test_msg_version(MessageTestCase): 32 | def test_serialization(self): 33 | super(Test_msg_version, self).serialization_test(msg_version) 34 | 35 | 36 | class Test_msg_verack(MessageTestCase): 37 | def test_serialization(self): 38 | super(Test_msg_verack, self).serialization_test(msg_verack) 39 | 40 | 41 | class Test_msg_addr(MessageTestCase): 42 | def test_serialization(self): 43 | super(Test_msg_addr, self).serialization_test(msg_addr) 44 | 45 | 46 | class Test_msg_alert(MessageTestCase): 47 | def test_serialization(self): 48 | super(Test_msg_alert, self).serialization_test(msg_alert) 49 | 50 | 51 | class Test_msg_inv(MessageTestCase): 52 | def test_serialization(self): 53 | super(Test_msg_inv, self).serialization_test(msg_inv) 54 | 55 | 56 | class Test_msg_getdata(MessageTestCase): 57 | def test_serialization(self): 58 | super(Test_msg_getdata, self).serialization_test(msg_getdata) 59 | 60 | 61 | class Test_msg_getblocks(MessageTestCase): 62 | def test_serialization(self): 63 | super(Test_msg_getblocks, self).serialization_test(msg_getblocks) 64 | 65 | 66 | class Test_msg_notfound(MessageTestCase): 67 | def test_serialization(self): 68 | super(Test_msg_notfound, self).serialization_test(msg_notfound) 69 | 70 | 71 | class Test_msg_getheaders(MessageTestCase): 72 | def test_serialization(self): 73 | super(Test_msg_getheaders, self).serialization_test(msg_getheaders) 74 | 75 | 76 | class Test_msg_headers(MessageTestCase): 77 | def test_serialization(self): 78 | super(Test_msg_headers, self).serialization_test(msg_headers) 79 | 80 | 81 | class Test_msg_tx(MessageTestCase): 82 | def test_serialization(self): 83 | super(Test_msg_tx, self).serialization_test(msg_tx) 84 | 85 | 86 | class Test_msg_block(MessageTestCase): 87 | def test_serialization(self): 88 | super(Test_msg_block, self).serialization_test(msg_block) 89 | 90 | 91 | class Test_msg_getaddr(MessageTestCase): 92 | def test_serialization(self): 93 | super(Test_msg_getaddr, self).serialization_test(msg_getaddr) 94 | 95 | 96 | class Test_msg_ping(MessageTestCase): 97 | def test_serialization(self): 98 | super(Test_msg_ping, self).serialization_test(msg_ping) 99 | 100 | 101 | class Test_msg_pong(MessageTestCase): 102 | def test_serialization(self): 103 | super(Test_msg_pong, self).serialization_test(msg_pong) 104 | 105 | 106 | class Test_msg_reject(MessageTestCase): 107 | def test_serialization(self): 108 | super(Test_msg_reject, self).serialization_test(msg_reject) 109 | 110 | 111 | class Test_msg_mempool(MessageTestCase): 112 | def test_serialization(self): 113 | super(Test_msg_mempool, self).serialization_test(msg_mempool) 114 | 115 | 116 | class Test_messages(unittest.TestCase): 117 | verackbytes = b'\xf9\xbe\xb4\xd9verack\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xf6\xe0\xe2' 118 | 119 | def test_read_msg_verack(self): 120 | f = BytesIO(self.verackbytes) 121 | m = MsgSerializable.stream_deserialize(f) 122 | self.assertEqual(m.command, msg_verack.command) 123 | 124 | def test_fail_invalid_message(self): 125 | bad_verack_bytes = b'\xf8' + self.verackbytes[1:] 126 | f = BytesIO(bad_verack_bytes) 127 | with self.assertRaises(ValueError): 128 | MsgSerializable.stream_deserialize(f) 129 | 130 | def test_msg_verack_to_bytes(self): 131 | m = msg_verack() 132 | b = m.to_bytes() 133 | self.assertEqual(self.verackbytes, b) 134 | -------------------------------------------------------------------------------- /bitcoin/tests/test_net.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | import unittest 13 | 14 | from bitcoin.net import CAddress, CAlert, CUnsignedAlert, CInv 15 | 16 | from io import BytesIO 17 | 18 | 19 | class TestUnsignedAlert(unittest.TestCase): 20 | def test_serialization(self): 21 | alert = CUnsignedAlert() 22 | alert.setCancel = [1, 2, 3] 23 | alert.strComment = b"Comment" 24 | stream = BytesIO() 25 | 26 | alert.stream_serialize(stream) 27 | serialized = BytesIO(stream.getvalue()) 28 | 29 | deserialized = CUnsignedAlert.stream_deserialize(serialized) 30 | self.assertEqual(deserialized, alert) 31 | 32 | 33 | class TestCAlert(unittest.TestCase): 34 | def test_serialization(self): 35 | alert = CAlert() 36 | alert.setCancel = [1, 2, 3] 37 | alert.strComment = b"Comment" 38 | stream = BytesIO() 39 | 40 | alert.stream_serialize(stream) 41 | serialized = BytesIO(stream.getvalue()) 42 | 43 | deserialized = CAlert.stream_deserialize(serialized) 44 | self.assertEqual(deserialized, alert) 45 | 46 | 47 | class TestCInv(unittest.TestCase): 48 | def test_serialization(self): 49 | inv = CInv() 50 | inv.type = 123 51 | inv.hash = b"0" * 32 52 | stream = BytesIO() 53 | 54 | inv.stream_serialize(stream) 55 | serialized = BytesIO(stream.getvalue()) 56 | 57 | deserialized = CInv.stream_deserialize(serialized) 58 | self.assertEqual(deserialized, inv) 59 | 60 | 61 | class TestCAddress(unittest.TestCase): 62 | def test_serializationSimple(self): 63 | c = CAddress() 64 | cSerialized = c.serialize() 65 | cDeserialized = CAddress.deserialize(cSerialized) 66 | cSerializedTwice = cDeserialized.serialize() 67 | self.assertEqual(cSerialized, cSerializedTwice) 68 | 69 | def test_serializationIPv4(self): 70 | c = CAddress() 71 | c.ip = "1.1.1.1" 72 | c.port = 8333 73 | c.nTime = 1420576401 74 | 75 | cSerialized = c.serialize() 76 | cDeserialized = CAddress.deserialize(cSerialized) 77 | 78 | self.assertEqual(c, cDeserialized) 79 | 80 | cSerializedTwice = cDeserialized.serialize() 81 | self.assertEqual(cSerialized, cSerializedTwice) 82 | 83 | def test_serializationIPv6(self): 84 | c = CAddress() 85 | c.ip = "1234:ABCD:1234:ABCD:1234:00:ABCD:1234" 86 | c.port = 8333 87 | c.nTime = 1420576401 88 | 89 | cSerialized = c.serialize() 90 | cDeserialized = CAddress.deserialize(cSerialized) 91 | 92 | self.assertEqual(c, cDeserialized) 93 | 94 | cSerializedTwice = cDeserialized.serialize() 95 | self.assertEqual(cSerialized, cSerializedTwice) 96 | 97 | def test_serializationDiff(self): 98 | # Sanity check that the serialization code preserves differences 99 | c1 = CAddress() 100 | c1.ip = "1.1.1.1" 101 | c1.port = 8333 102 | c1.nTime = 1420576401 103 | 104 | c2 = CAddress() 105 | c2.ip = "1.1.1.2" 106 | c2.port = 8333 107 | c2.nTime = 1420576401 108 | 109 | self.assertNotEqual(c1, c2) 110 | 111 | c1Serialized = c1.serialize() 112 | c2Serialized = c2.serialize() 113 | 114 | self.assertNotEqual(c1Serialized, c2Serialized) 115 | 116 | c1Deserialized = CAddress.deserialize(c1Serialized) 117 | c2Deserialized = CAddress.deserialize(c2Serialized) 118 | 119 | self.assertNotEqual(c1Deserialized, c2Deserialized) 120 | -------------------------------------------------------------------------------- /bitcoin/tests/test_ripemd160.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from bitcoin.core.contrib.ripemd160 import ripemd160 4 | 5 | 6 | class Test_ripemd160(unittest.TestCase): 7 | def test_ripemd160(self): 8 | """RIPEMD-160 test vectors.""" 9 | # See https://homes.esat.kuleuven.be/~bosselae/ripemd160.html 10 | for msg, hexout in [ 11 | (b"", "9c1185a5c5e9fc54612808977ee8f548b2258d31"), 12 | (b"a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"), 13 | (b"abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"), 14 | (b"message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36"), 15 | (b"abcdefghijklmnopqrstuvwxyz", 16 | "f71c27109c692c1b56bbdceb5b9d2865b3708dbc"), 17 | (b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 18 | "12a053384a9c0c88e405a06c27dcf49ada62eb2b"), 19 | (b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 20 | "b0e20b6e3116640286ed3a87a5713079b21f5189"), 21 | (b"1234567890" * 8, "9b752e45573d4b39f4dbd3323cab82bf63326bfb"), 22 | (b"a" * 1000000, "52783243c1697bdbe16d37f97f68f08325dc1528") 23 | ]: 24 | self.assertEqual(ripemd160(msg).hex(), hexout) 25 | -------------------------------------------------------------------------------- /bitcoin/tests/test_rpc.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import unittest 14 | 15 | from bitcoin.rpc import Proxy 16 | 17 | class Test_RPC(unittest.TestCase): 18 | # Tests disabled, see discussion below. 19 | # "Looks like your unit tests won't work if Bitcoin Core isn't running; 20 | # maybe they in turn need to check that and disable the test if core isn't available?" 21 | # https://github.com/petertodd/python-bitcoinlib/pull/10 22 | pass 23 | 24 | # def test_can_validate(self): 25 | # working_address = '1CB2fxLGAZEzgaY4pjr4ndeDWJiz3D3AT7' 26 | # p = Proxy() 27 | # r = p.validateAddress(working_address) 28 | # self.assertEqual(r['address'], working_address) 29 | # self.assertEqual(r['isvalid'], True) 30 | # 31 | # def test_cannot_validate(self): 32 | # non_working_address = 'LTatMHrYyHcxhxrY27AqFN53bT4TauR86h' 33 | # p = Proxy() 34 | # r = p.validateAddress(non_working_address) 35 | # self.assertEqual(r['isvalid'], False) 36 | -------------------------------------------------------------------------------- /bitcoin/tests/test_scripteval.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import json 14 | import os 15 | import unittest 16 | 17 | from binascii import unhexlify 18 | 19 | from bitcoin.core import * 20 | from bitcoin.core.script import * 21 | from bitcoin.core.scripteval import * 22 | 23 | def parse_script(s): 24 | def ishex(s): 25 | return set(s).issubset(set('0123456789abcdefABCDEF')) 26 | 27 | r = [] 28 | 29 | # Create an opcodes_by_name table with both OP_ prefixed names and 30 | # shortened ones with the OP_ dropped. 31 | opcodes_by_name = {} 32 | for name, code in OPCODES_BY_NAME.items(): 33 | opcodes_by_name[name] = code 34 | opcodes_by_name[name[3:]] = code 35 | 36 | for word in s.split(): 37 | if word.isdigit() or (word[0] == '-' and word[1:].isdigit()): 38 | r.append(CScript([int(word)])) 39 | elif word.startswith('0x') and ishex(word[2:]): 40 | # Raw ex data, inserted NOT pushed onto stack: 41 | r.append(unhexlify(word[2:].encode('utf8'))) 42 | elif len(word) >= 2 and word[0] == "'" and word[-1] == "'": 43 | r.append(CScript([bytes(word[1:-1].encode('utf8'))])) 44 | elif word in opcodes_by_name: 45 | r.append(CScript([opcodes_by_name[word]])) 46 | else: 47 | raise ValueError("Error parsing script: %r" % s) 48 | 49 | return CScript(b''.join(r)) 50 | 51 | 52 | def load_test_vectors(name): 53 | with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: 54 | for test_case in json.load(fd): 55 | if len(test_case) == 1: 56 | continue # comment 57 | 58 | if len(test_case) == 3: 59 | test_case.append('') # add missing comment 60 | 61 | scriptSig, scriptPubKey, flags, comment = test_case 62 | 63 | scriptSig = parse_script(scriptSig) 64 | scriptPubKey = parse_script(scriptPubKey) 65 | 66 | flag_set = set() 67 | for flag in flags.split(','): 68 | if flag == '' or flag == 'NONE': 69 | pass 70 | 71 | else: 72 | try: 73 | flag = SCRIPT_VERIFY_FLAGS_BY_NAME[flag] 74 | except IndexError: 75 | raise Exception('Unknown script verify flag %r' % flag) 76 | 77 | flag_set.add(flag) 78 | 79 | yield (scriptSig, scriptPubKey, flag_set, comment, test_case) 80 | 81 | 82 | class Test_EvalScript(unittest.TestCase): 83 | def create_test_txs(self, scriptSig, scriptPubKey): 84 | txCredit = CTransaction([CTxIn(COutPoint(), CScript([OP_0, OP_0]), nSequence=0xFFFFFFFF)], 85 | [CTxOut(0, scriptPubKey)], 86 | nLockTime=0) 87 | txSpend = CTransaction([CTxIn(COutPoint(txCredit.GetTxid(), 0), scriptSig, nSequence=0xFFFFFFFF)], 88 | [CTxOut(0, CScript())], 89 | nLockTime=0) 90 | return (txCredit, txSpend) 91 | 92 | def test_script_valid(self): 93 | for scriptSig, scriptPubKey, flags, comment, test_case in load_test_vectors('script_valid.json'): 94 | (txCredit, txSpend) = self.create_test_txs(scriptSig, scriptPubKey) 95 | 96 | try: 97 | VerifyScript(scriptSig, scriptPubKey, txSpend, 0, flags) 98 | except ValidationError as err: 99 | self.fail('Script FAILED: %r %r %r with exception %r' % (scriptSig, scriptPubKey, comment, err)) 100 | 101 | def test_script_invalid(self): 102 | for scriptSig, scriptPubKey, flags, comment, test_case in load_test_vectors('script_invalid.json'): 103 | (txCredit, txSpend) = self.create_test_txs(scriptSig, scriptPubKey) 104 | 105 | try: 106 | VerifyScript(scriptSig, scriptPubKey, txSpend, 0, flags) 107 | except ValidationError: 108 | continue 109 | 110 | self.fail('Expected %r to fail' % test_case) 111 | -------------------------------------------------------------------------------- /bitcoin/tests/test_segwit.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import unittest 14 | import random 15 | import sys 16 | 17 | import bitcoin 18 | from bitcoin.core import * 19 | from bitcoin.core.script import * 20 | from bitcoin.wallet import * 21 | 22 | # Test serialization 23 | 24 | 25 | class Test_Segwit(unittest.TestCase): 26 | 27 | # Test BIP 143 vectors 28 | def test_p2wpkh_signaturehash(self): 29 | unsigned_tx = x('0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000') 30 | scriptpubkey = CScript(x('00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1')) 31 | value = int(6*COIN) 32 | 33 | address = CBech32BitcoinAddress.from_scriptPubKey(scriptpubkey) 34 | self.assertEqual(SignatureHash(address.to_redeemScript(), CTransaction.deserialize(unsigned_tx), 35 | 1, SIGHASH_ALL, value, SIGVERSION_WITNESS_V0), 36 | x('c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')) 37 | 38 | def test_p2sh_p2wpkh_signaturehash(self): 39 | unsigned_tx = x('0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000') 40 | scriptpubkey = CScript(x('a9144733f37cf4db86fbc2efed2500b4f4e49f31202387')) 41 | redeemscript = CScript(x('001479091972186c449eb1ded22b78e40d009bdf0089')) 42 | value = int(10*COIN) 43 | 44 | address = CBase58BitcoinAddress.from_scriptPubKey(redeemscript) 45 | self.assertEqual(SignatureHash(address.to_redeemScript(), CTransaction.deserialize(unsigned_tx), 46 | 0, SIGHASH_ALL, value, SIGVERSION_WITNESS_V0), 47 | x('64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6')) 48 | 49 | def test_p2wsh_signaturehash1(self): 50 | unsigned_tx = x('0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000') 51 | scriptpubkey1 = CScript(x('21036d5c20fa14fb2f635474c1dc4ef5909d4568e5569b79fc94d3448486e14685f8ac')) 52 | value1 = int(1.5625*COIN) 53 | scriptpubkey2 = CScript(x('00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0')) 54 | value2 = int(49*COIN) 55 | scriptcode1 = CScript(x('21026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac')) 56 | # This is the same script with everything up to the last executed OP_CODESEPARATOR, including that 57 | # OP_CODESEPARATOR removed 58 | scriptcode2 = CScript(x('210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac')) 59 | 60 | self.assertEqual(SignatureHash(scriptcode1, CTransaction.deserialize(unsigned_tx), 61 | 1, SIGHASH_SINGLE, value2, SIGVERSION_WITNESS_V0), 62 | x('82dde6e4f1e94d02c2b7ad03d2115d691f48d064e9d52f58194a6637e4194391')) 63 | self.assertEqual(SignatureHash(scriptcode2, CTransaction.deserialize(unsigned_tx), 64 | 1, SIGHASH_SINGLE, value2, SIGVERSION_WITNESS_V0), 65 | x('fef7bd749cce710c5c052bd796df1af0d935e59cea63736268bcbe2d2134fc47')) 66 | 67 | def test_p2wsh_signaturehash2(self): 68 | unsigned_tx = x('0100000002e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac00000000') 69 | scriptpubkey1 = CScript(x('0020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d')) 70 | value1 = int(0.16777215*COIN) 71 | witnessscript1= CScript(x('0063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac')) 72 | scriptcode1 = CScript(x('0063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac')) 73 | scriptpubkey2 = CScript(x('0020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537')) 74 | value2 = int(0.16777215*COIN) 75 | witnessscript2= CScript(x('5163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac')) 76 | scriptcode2 = CScript(x('68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac')) 77 | 78 | self.assertEqual(SignatureHash(scriptcode1, CTransaction.deserialize(unsigned_tx), 79 | 0, SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, value1, SIGVERSION_WITNESS_V0), 80 | x('e9071e75e25b8a1e298a72f0d2e9f4f95a0f5cdf86a533cda597eb402ed13b3a')) 81 | self.assertEqual(SignatureHash(scriptcode2, CTransaction.deserialize(unsigned_tx), 82 | 1, SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, value2, SIGVERSION_WITNESS_V0), 83 | x('cd72f1f1a433ee9df816857fad88d8ebd97e09a75cd481583eb841c330275e54')) 84 | 85 | def test_p2sh_p2wsh_signaturehash(self): 86 | unsigned_tx = x('010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000') 87 | 88 | scriptPubKey = CScript(x('a9149993a429037b5d912407a71c252019287b8d27a587')) 89 | value = int(9.87654321*COIN) 90 | redeemScript = CScript(x('0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54')) 91 | witnessscript= CScript(x('56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae')) 92 | 93 | self.assertEqual(SignatureHash(witnessscript, CTransaction.deserialize(unsigned_tx), 94 | 0, SIGHASH_ALL, value, SIGVERSION_WITNESS_V0), 95 | x('185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c')) 96 | self.assertEqual(SignatureHash(witnessscript, CTransaction.deserialize(unsigned_tx), 97 | 0, SIGHASH_NONE, value, SIGVERSION_WITNESS_V0), 98 | x('e9733bc60ea13c95c6527066bb975a2ff29a925e80aa14c213f686cbae5d2f36')) 99 | self.assertEqual(SignatureHash(witnessscript, CTransaction.deserialize(unsigned_tx), 100 | 0, SIGHASH_SINGLE, value, SIGVERSION_WITNESS_V0), 101 | x('1e1f1c303dc025bd664acb72e583e933fae4cff9148bf78c157d1e8f78530aea')) 102 | self.assertEqual(SignatureHash(witnessscript, CTransaction.deserialize(unsigned_tx), 103 | 0, SIGHASH_ALL|SIGHASH_ANYONECANPAY, value, SIGVERSION_WITNESS_V0), 104 | x('2a67f03e63a6a422125878b40b82da593be8d4efaafe88ee528af6e5a9955c6e')) 105 | self.assertEqual(SignatureHash(witnessscript, CTransaction.deserialize(unsigned_tx), 106 | 0, SIGHASH_NONE|SIGHASH_ANYONECANPAY, value, SIGVERSION_WITNESS_V0), 107 | x('781ba15f3779d5542ce8ecb5c18716733a5ee42a6f51488ec96154934e2c890a')) 108 | self.assertEqual(SignatureHash(witnessscript, CTransaction.deserialize(unsigned_tx), 109 | 0, SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, value, SIGVERSION_WITNESS_V0), 110 | x('511e8e52ed574121fc1b654970395502128263f62662e076dc6baf05c2e6a99b')) 111 | 112 | def test_checkblock(self): 113 | # (No witness) coinbase generated by Bitcoin Core 114 | str_coinbase = '01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff03520101ffffffff0100f2052a01000000232102960c90bc04a631cb17922e4f5d80ac75fd590a88b8baaa5a3d5086ac85e4d788ac00000000' 115 | # No witness transaction 116 | str_tx = '0100000001e3d0c1d051a3abe79d5951dcab86f71d8926aff5caed5ff9bd72cb593e4ebaf5010000006b483045022100a28e1c57e160296953e1af85c5034bb1b907c12c50367da75ba547874a8a8c52022040682e888ddce7fd5c72519a9f28f22f5164c8af864d33332bbc7f65596ad4ae012102db30394fd5cc8288bed607b9382338240c014a98c9c0febbfb380db74ceb30a3ffffffff020d920000000000001976a914ad781c8ffcc18b2155433cba2da4601180a66eef88aca3170000000000001976a914bacb1c4b0725e61e385c7093b4260533953c8e1688ac00000000' 117 | # SegWit transaction 118 | str_w_tx = '0100000000010115e180dc28a2327e687facc33f10f2a20da717e5548406f7ae8b4c811072f8560100000000ffffffff0100b4f505000000001976a9141d7cd6c75c2e86f4cbf98eaed221b30bd9a0b92888ac02483045022100df7b7e5cda14ddf91290e02ea10786e03eb11ee36ec02dd862fe9a326bbcb7fd02203f5b4496b667e6e281cc654a2da9e4f08660c620a1051337fa8965f727eb19190121038262a6c6cec93c2d3ecd6c6072efea86d02ff8e3328bbd0242b20af3425990ac00000000' 119 | witness_nonce = bytes(random.getrandbits(8) for _ in range(32)) 120 | 121 | coinbase = CMutableTransaction.deserialize(x(str_coinbase)) 122 | coinbase.wit = CTxWitness([CTxInWitness(CScriptWitness([witness_nonce]))]) 123 | 124 | tx_legacy = CTransaction.deserialize(x(str_tx)) 125 | tx_segwit = CTransaction.deserialize(x(str_w_tx)) 126 | 127 | witness_merkle_root = CBlock.build_witness_merkle_tree_from_txs((coinbase, tx_legacy, tx_segwit))[-1] 128 | 129 | commitment = Hash(witness_merkle_root + witness_nonce) 130 | commitment_script = bitcoin.core.WITNESS_COINBASE_SCRIPTPUBKEY_MAGIC + commitment 131 | coinbase.vout.append(CTxOut(0, CScript(commitment_script))) 132 | 133 | block = CBlock(2, b'\x00'*32, b'\x00'*32, 0, 0, 0, (coinbase, tx_legacy, tx_segwit)) 134 | 135 | CheckBlock(block, False, True) 136 | -------------------------------------------------------------------------------- /bitcoin/tests/test_serialize.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import unittest, random 14 | 15 | from binascii import unhexlify 16 | 17 | from bitcoin.core.serialize import * 18 | 19 | class Test_Serializable(unittest.TestCase): 20 | def test_extra_data(self): 21 | """Serializable.deserialize() fails if extra data is present""" 22 | 23 | class FooSerializable(Serializable): 24 | @classmethod 25 | def stream_deserialize(cls, f): 26 | return cls() 27 | 28 | def stream_serialize(self, f): 29 | pass 30 | 31 | try: 32 | FooSerializable.deserialize(b'\x00') 33 | except DeserializationExtraDataError as err: 34 | self.assertEqual(err.obj, FooSerializable()) 35 | self.assertEqual(err.padding, b'\x00') 36 | 37 | else: 38 | self.fail("DeserializationExtraDataError not raised") 39 | 40 | FooSerializable.deserialize(b'\x00', allow_padding=True) 41 | 42 | class Test_VarIntSerializer(unittest.TestCase): 43 | def test(self): 44 | def T(value, expected): 45 | expected = unhexlify(expected) 46 | actual = VarIntSerializer.serialize(value) 47 | self.assertEqual(actual, expected) 48 | roundtrip = VarIntSerializer.deserialize(actual) 49 | self.assertEqual(value, roundtrip) 50 | T(0x0, b'00') 51 | T(0xfc, b'fc') 52 | T(0xfd, b'fdfd00') 53 | T(0xffff, b'fdffff') 54 | T(0x10000, b'fe00000100') 55 | T(0xffffffff, b'feffffffff') 56 | T(0x100000000, b'ff0000000001000000') 57 | T(0xffffffffffffffff, b'ffffffffffffffffff') 58 | 59 | def test_non_optimal(self): 60 | def T(serialized, expected_value): 61 | serialized = unhexlify(serialized) 62 | actual_value = VarIntSerializer.deserialize(serialized) 63 | self.assertEqual(actual_value, expected_value) 64 | T(b'fd0000', 0) 65 | T(b'fd3412', 0x1234) 66 | T(b'fe00000000', 0) 67 | T(b'fe67452301', 0x1234567) 68 | T(b'ff0000000000000000', 0) 69 | T(b'ffefcdab8967452301', 0x123456789abcdef) 70 | 71 | def test_truncated(self): 72 | def T(serialized): 73 | serialized = unhexlify(serialized) 74 | with self.assertRaises(SerializationTruncationError): 75 | VarIntSerializer.deserialize(serialized) 76 | T(b'') 77 | T(b'fd') 78 | T(b'fd00') 79 | T(b'fe') 80 | T(b'fe00') 81 | T(b'fe0000') 82 | T(b'fe000000') 83 | T(b'ff') 84 | T(b'ff00000000000000') 85 | 86 | class Test_BytesSerializer(unittest.TestCase): 87 | def test(self): 88 | def T(value, expected): 89 | value = unhexlify(value) 90 | expected = unhexlify(expected) 91 | actual = BytesSerializer.serialize(value) 92 | self.assertEqual(actual, expected) 93 | roundtrip = BytesSerializer.deserialize(actual) 94 | self.assertEqual(value, roundtrip) 95 | T(b'', b'00') 96 | T(b'00', b'0100') 97 | T(b'00'*0xffff, b'fdffff' + b'00'*0xffff) 98 | 99 | def test_truncated(self): 100 | def T(serialized, ex_cls=SerializationTruncationError): 101 | serialized = unhexlify(serialized) 102 | with self.assertRaises(ex_cls): 103 | BytesSerializer.deserialize(serialized) 104 | T(b'') 105 | T(b'01') 106 | T(b'0200') 107 | T(b'ff00000000000000ff11223344', SerializationError) # > max_size 108 | 109 | class Test_Compact(unittest.TestCase): 110 | def test_from_compact_zero(self): 111 | self.assertEqual(uint256_from_compact(0x00123456), 0) 112 | self.assertEqual(uint256_from_compact(0x01003456), 0) 113 | self.assertEqual(uint256_from_compact(0x02000056), 0) 114 | self.assertEqual(uint256_from_compact(0x03000000), 0) 115 | self.assertEqual(uint256_from_compact(0x04000000), 0) 116 | self.assertEqual(uint256_from_compact(0x00923456), 0) 117 | def test_from_compact_negative_zero(self): 118 | # Negative bit isn't supported yet 119 | # self.assertEqual(uint256_from_compact(0x01803456), 0) 120 | # self.assertEqual(uint256_from_compact(0x02800056), 0) 121 | # self.assertEqual(uint256_from_compact(0x03800000), 0) 122 | # self.assertEqual(uint256_from_compact(0x04800000), 0) 123 | return 124 | 125 | def test_twelve(self): 126 | self.assertEqual(uint256_from_compact(0x01123456), 0x0012) 127 | self.assertEqual(compact_from_uint256(0x0012), 0x01120000) 128 | 129 | def test_from_uint256(self): 130 | self.assertEqual(compact_from_uint256(0x1234), 0x02123400) 131 | self.assertEqual(compact_from_uint256(0x123456), 0x03123456) 132 | self.assertEqual(compact_from_uint256(0x12345600), 0x04123456) 133 | self.assertEqual(compact_from_uint256(0x92340000), 0x05009234) 134 | self.assertEqual(compact_from_uint256(0x1234560000000000000000000000000000000000000000000000000000000000), 0x20123456) 135 | 136 | class Test_Uint256_Serialize(unittest.TestCase): 137 | def test_fixed(self): 138 | values = [] 139 | values.append(0) 140 | values.append(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) 141 | for x in range(100): 142 | values.append(random.getrandbits(256)) 143 | for n in values: 144 | assert(uint256_from_str(uint256_to_str(n)) == n) 145 | 146 | -------------------------------------------------------------------------------- /bitcoin/tests/test_signmessage.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import unittest 14 | 15 | from bitcoin.wallet import CBitcoinSecret 16 | from bitcoin.signmessage import BitcoinMessage, VerifyMessage, SignMessage 17 | import os 18 | import json 19 | 20 | def load_test_vectors(name): 21 | with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: 22 | return json.load(fd) 23 | 24 | 25 | class Test_SignVerifyMessage(unittest.TestCase): 26 | def test_verify_message_simple(self): 27 | address = "1F26pNMrywyZJdr22jErtKcjF8R3Ttt55G" 28 | message = address 29 | signature = "H85WKpqtNZDrajOnYDgUY+abh0KCAcOsAIOQwx2PftAbLEPRA7mzXA/CjXRxzz0MC225pR/hx02Vf2Ag2x33kU4=" 30 | 31 | message = BitcoinMessage(message) 32 | 33 | self.assertTrue(VerifyMessage(address, message, signature)) 34 | 35 | def test_verify_message_vectors(self): 36 | for vector in load_test_vectors('signmessage.json'): 37 | message = BitcoinMessage(vector['address']) 38 | self.assertTrue(VerifyMessage(vector['address'], message, vector['signature'])) 39 | 40 | def test_sign_message_simple(self): 41 | key = CBitcoinSecret("L4vB5fomsK8L95wQ7GFzvErYGht49JsCPJyJMHpB4xGM6xgi2jvG") 42 | address = "1F26pNMrywyZJdr22jErtKcjF8R3Ttt55G" 43 | message = address 44 | 45 | message = BitcoinMessage(message) 46 | signature = SignMessage(key, message) 47 | 48 | self.assertTrue(signature) 49 | self.assertTrue(VerifyMessage(address, message, signature)) 50 | 51 | def test_sign_message_vectors(self): 52 | for vector in load_test_vectors('signmessage.json'): 53 | key = CBitcoinSecret(vector['wif']) 54 | message = BitcoinMessage(vector['address']) 55 | 56 | signature = SignMessage(key, message) 57 | 58 | self.assertTrue(signature, "Failed to sign for [%s]" % vector['address']) 59 | self.assertTrue(VerifyMessage(vector['address'], message, vector['signature']), "Failed to verify signature for [%s]" % vector['address']) 60 | 61 | 62 | if __name__ == "__main__": 63 | unittest.main() 64 | -------------------------------------------------------------------------------- /bitcoin/tests/test_transactions.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) The python-bitcoinlib developers 2 | # 3 | # This file is part of python-bitcoinlib. 4 | # 5 | # It is subject to the license terms in the LICENSE file found in the top-level 6 | # directory of this distribution. 7 | # 8 | # No part of python-bitcoinlib, including this file, may be copied, modified, 9 | # propagated, or distributed except according to the terms contained in the 10 | # LICENSE file. 11 | 12 | 13 | import json 14 | import unittest 15 | import os 16 | 17 | from bitcoin.core import * 18 | from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH 19 | 20 | from bitcoin.tests.test_scripteval import parse_script 21 | 22 | def load_test_vectors(name): 23 | with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: 24 | for test_case in json.load(fd): 25 | # Comments designated by single length strings 26 | if len(test_case) == 1: 27 | continue 28 | assert len(test_case) == 3 29 | 30 | prevouts = {} 31 | for json_prevout in test_case[0]: 32 | assert len(json_prevout) == 3 33 | n = json_prevout[1] 34 | if n == -1: 35 | n = 0xffffffff 36 | prevout = COutPoint(lx(json_prevout[0]), n) 37 | prevouts[prevout] = parse_script(json_prevout[2]) 38 | 39 | tx = CTransaction.deserialize(x(test_case[1])) 40 | enforceP2SH = test_case[2] 41 | 42 | yield (prevouts, tx, enforceP2SH) 43 | 44 | class Test_COutPoint(unittest.TestCase): 45 | def test_is_null(self): 46 | self.assertTrue(COutPoint().is_null()) 47 | self.assertTrue(COutPoint(hash=b'\x00'*32,n=0xffffffff).is_null()) 48 | self.assertFalse(COutPoint(hash=b'\x00'*31 + b'\x01').is_null()) 49 | self.assertFalse(COutPoint(n=1).is_null()) 50 | 51 | def test_repr(self): 52 | def T(outpoint, expected): 53 | actual = repr(outpoint) 54 | self.assertEqual(actual, expected) 55 | T( COutPoint(), 56 | 'COutPoint()') 57 | T( COutPoint(lx('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'), 0), 58 | "COutPoint(lx('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'), 0)") 59 | 60 | def test_str(self): 61 | def T(outpoint, expected): 62 | actual = str(outpoint) 63 | self.assertEqual(actual, expected) 64 | T(COutPoint(), 65 | '0000000000000000000000000000000000000000000000000000000000000000:4294967295') 66 | T(COutPoint(lx('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'), 0), 67 | '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0') 68 | T(COutPoint(lx('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'), 10), 69 | '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:10') 70 | 71 | class Test_CMutableOutPoint(unittest.TestCase): 72 | def test_GetHash(self): 73 | """CMutableOutPoint.GetHash() is not cached""" 74 | outpoint = CMutableOutPoint() 75 | 76 | h1 = outpoint.GetHash() 77 | outpoint.n = 1 78 | 79 | self.assertNotEqual(h1, outpoint.GetHash()) 80 | 81 | 82 | class Test_CTxIn(unittest.TestCase): 83 | def test_is_final(self): 84 | self.assertTrue(CTxIn().is_final()) 85 | self.assertTrue(CTxIn(nSequence=0xffffffff).is_final()) 86 | self.assertFalse(CTxIn(nSequence=0).is_final()) 87 | 88 | def test_repr(self): 89 | def T(txin, expected): 90 | actual = repr(txin) 91 | self.assertEqual(actual, expected) 92 | T( CTxIn(), 93 | 'CTxIn(COutPoint(), CScript([]), 0xffffffff)') 94 | 95 | class Test_CMutableTxIn(unittest.TestCase): 96 | def test_GetHash(self): 97 | """CMutableTxIn.GetHash() is not cached""" 98 | txin = CMutableTxIn() 99 | 100 | h1 = txin.GetHash() 101 | txin.prevout.n = 1 102 | 103 | self.assertNotEqual(h1, txin.GetHash()) 104 | 105 | class Test_CTransaction(unittest.TestCase): 106 | def test_is_coinbase(self): 107 | tx = CMutableTransaction() 108 | self.assertFalse(tx.is_coinbase()) 109 | 110 | tx.vin.append(CMutableTxIn()) 111 | 112 | # IsCoinBase() in reference client doesn't check if vout is empty 113 | self.assertTrue(tx.is_coinbase()) 114 | 115 | tx.vin[0].prevout.n = 0 116 | self.assertFalse(tx.is_coinbase()) 117 | 118 | tx.vin[0] = CTxIn() 119 | tx.vin.append(CTxIn()) 120 | self.assertFalse(tx.is_coinbase()) 121 | 122 | def test_tx_valid(self): 123 | for prevouts, tx, enforceP2SH in load_test_vectors('tx_valid.json'): 124 | try: 125 | CheckTransaction(tx) 126 | except CheckTransactionError: 127 | self.fail('tx failed CheckTransaction(): ' \ 128 | + str((prevouts, b2x(tx.serialize()), enforceP2SH))) 129 | continue 130 | 131 | for i in range(len(tx.vin)): 132 | flags = set() 133 | if enforceP2SH: 134 | flags.add(SCRIPT_VERIFY_P2SH) 135 | 136 | VerifyScript(tx.vin[i].scriptSig, prevouts[tx.vin[i].prevout], tx, i, flags=flags) 137 | 138 | 139 | def test_tx_invalid(self): 140 | for prevouts, tx, enforceP2SH in load_test_vectors('tx_invalid.json'): 141 | try: 142 | CheckTransaction(tx) 143 | except CheckTransactionError: 144 | continue 145 | 146 | with self.assertRaises(ValidationError): 147 | for i in range(len(tx.vin)): 148 | flags = set() 149 | if enforceP2SH: 150 | flags.add(SCRIPT_VERIFY_P2SH) 151 | 152 | VerifyScript(tx.vin[i].scriptSig, prevouts[tx.vin[i].prevout], tx, i, flags=flags) 153 | 154 | def test_calc_weight(self): 155 | # test vectors taken from rust-bitcoin 156 | txs = [ 157 | # one segwit input (P2WPKH) 158 | ('020000000001018a763b78d3e17acea0625bf9e52b0dc1beb2241b2502185348ba8ff4a253176e0100000000ffffffff0280d725000000000017a914c07ed639bd46bf7087f2ae1dfde63b815a5f8b488767fda20300000000160014869ec8520fa2801c8a01bfdd2e82b19833cd0daf02473044022016243edad96b18c78b545325aaff80131689f681079fb107a67018cb7fb7830e02205520dae761d89728f73f1a7182157f6b5aecf653525855adb7ccb998c8e6143b012103b9489bde92afbcfa85129a82ffa512897105d1a27ad9806bded27e0532fc84e700000000', 565), 159 | # one segwit input (P2WSH) 160 | ('01000000000101a3ccad197118a2d4975fadc47b90eacfdeaf8268adfdf10ed3b4c3b7e1ad14530300000000ffffffff0200cc5501000000001976a91428ec6f21f4727bff84bb844e9697366feeb69f4d88aca2a5100d00000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220548f11130353b3a8f943d2f14260345fc7c20bde91704c9f1cbb5456355078cd0220383ed4ed39b079b618bcb279bbc1f2ca18cb028c4641cb522c9c5868c52a0dc20147304402203c332ecccb3181ca82c0600520ee51fee80d3b4a6ab110945e59475ec71e44ac0220679a11f3ca9993b04ccebda3c834876f353b065bb08f50076b25f5bb93c72ae1016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000', 766), 161 | # one segwit input (P2WPKH) and two legacy inputs (P2PKH) 162 | ('010000000001036b6b6ac7e34e97c53c1cc74c99c7948af2e6aac75d8778004ae458d813456764000000006a473044022001deec7d9075109306320b3754188f81a8236d0d232b44bc69f8309115638b8f02204e17a5194a519cf994d0afeea1268740bdc10616b031a521113681cc415e815c012103488d3272a9fad78ee887f0684cb8ebcfc06d0945e1401d002e590c7338b163feffffffffc75bd7aa6424aee972789ec28ba181254ee6d8311b058d165bd045154d7660b0000000006b483045022100c8641bcbee3e4c47a00417875015d8c5d5ea918fb7e96f18c6ffe51bc555b401022074e2c46f5b1109cd79e39a9aa203eadd1d75356415e51d80928a5fb5feb0efee0121033504b4c6dfc3a5daaf7c425aead4c2dbbe4e7387ce8e6be2648805939ecf7054ffffffff494df3b205cd9430a26f8e8c0dc0bb80496fbc555a524d6ea307724bc7e60eee0100000000ffffffff026d861500000000001976a9145c54ed1360072ebaf56e87693b88482d2c6a101588ace407000000000000160014761e31e2629c6e11936f2f9888179d60a5d4c1f900000247304402201fa38a67a63e58b67b6cfffd02f59121ca1c8a1b22e1efe2573ae7e4b4f06c2b022002b9b431b58f6e36b3334fb14eaecee7d2f06967a77ef50d8d5f90dda1057f0c01210257dc6ce3b1100903306f518ee8fa113d778e403f118c080b50ce079fba40e09a00000000', 1755), 163 | # three legacy inputs (P2PKH) 164 | ('0100000003e4d7be4314204a239d8e00691128dca7927e19a7339c7948bde56f669d27d797010000006b483045022100b988a858e2982e2daaf0755b37ad46775d6132057934877a5badc91dee2f66ff022020b967c1a2f0916007662ec609987e951baafa6d4fda23faaad70715611d6a2501210254a2dccd8c8832d4677dc6f0e562eaaa5d11feb9f1de2c50a33832e7c6190796ffffffff9e22eb1b3f24c260187d716a8a6c2a7efb5af14a30a4792a6eeac3643172379c000000006a47304402207df07f0cd30dca2cf7bed7686fa78d8a37fe9c2254dfdca2befed54e06b779790220684417b8ff9f0f6b480546a9e90ecee86a625b3ea1e4ca29b080da6bd6c5f67e01210254a2dccd8c8832d4677dc6f0e562eaaa5d11feb9f1de2c50a33832e7c6190796ffffffff1123df3bfb503b59769731da103d4371bc029f57979ebce68067768b958091a1000000006a47304402207a016023c2b0c4db9a7d4f9232fcec2193c2f119a69125ad5bcedcba56dd525e02206a734b3a321286c896759ac98ebfd9d808df47f1ce1fbfbe949891cc3134294701210254a2dccd8c8832d4677dc6f0e562eaaa5d11feb9f1de2c50a33832e7c6190796ffffffff0200c2eb0b000000001976a914e5eb3e05efad136b1405f5c2f9adb14e15a35bb488ac88cfff1b000000001976a9144846db516db3130b7a3c92253599edec6bc9630b88ac00000000', 2080), 165 | # one segwit input (P2TR) 166 | ('01000000000101b5cee87f1a60915c38bb0bc26aaf2b67be2b890bbc54bb4be1e40272e0d2fe0b0000000000ffffffff025529000000000000225120106daad8a5cb2e6fc74783714273bad554a148ca2d054e7a19250e9935366f3033760000000000002200205e6d83c44f57484fd2ef2a62b6d36cdcd6b3e06b661e33fd65588a28ad0dbe060141df9d1bfce71f90d68bf9e9461910b3716466bfe035c7dbabaa7791383af6c7ef405a3a1f481488a91d33cd90b098d13cb904323a3e215523aceaa04e1bb35cdb0100000000', 617), 167 | # one legacy input (P2PKH) 168 | ('0100000001c336895d9fa674f8b1e294fd006b1ac8266939161600e04788c515089991b50a030000006a47304402204213769e823984b31dcb7104f2c99279e74249eacd4246dabcf2575f85b365aa02200c3ee89c84344ae326b637101a92448664a8d39a009c8ad5d147c752cbe112970121028b1b44b4903c9103c07d5a23e3c7cf7aeb0ba45ddbd2cfdce469ab197381f195fdffffff040000000000000000536a4c5058325bb7b7251cf9e36cac35d691bd37431eeea426d42cbdecca4db20794f9a4030e6cb5211fabf887642bcad98c9994430facb712da8ae5e12c9ae5ff314127d33665000bb26c0067000bb0bf00322a50c300000000000017a9145ca04fdc0a6d2f4e3f67cfeb97e438bb6287725f8750c30000000000001976a91423086a767de0143523e818d4273ddfe6d9e4bbcc88acc8465003000000001976a914c95cbacc416f757c65c942f9b6b8a20038b9b12988ac00000000', 1396), 169 | ] 170 | 171 | for tx, expected_wu in txs: 172 | tx = CTransaction.deserialize(x(tx)) 173 | self.assertEqual(tx.calc_weight(), expected_wu) 174 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bitcoin.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bitcoin.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/bitcoin" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bitcoin" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /doc/_static/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petertodd/python-bitcoinlib/91e334d831fd16c60c932ad7df42c88fd6567c02/doc/_static/.placeholder -------------------------------------------------------------------------------- /doc/_templates/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petertodd/python-bitcoinlib/91e334d831fd16c60c932ad7df42c88fd6567c02/doc/_templates/.placeholder -------------------------------------------------------------------------------- /doc/bitcoin.core.rst: -------------------------------------------------------------------------------- 1 | bitcoin.core 2 | ============ 3 | 4 | Everything consensus critical is found in the core subpackage. 5 | 6 | :mod:`core` 7 | ----------- 8 | 9 | .. automodule:: bitcoin.core 10 | 11 | :mod:`key` 12 | ---------- 13 | 14 | .. automodule:: bitcoin.core.key 15 | 16 | :mod:`script` 17 | ------------- 18 | 19 | .. automodule:: bitcoin.core.script 20 | 21 | :mod:`scripteval` 22 | ----------------- 23 | 24 | .. automodule:: bitcoin.core.scripteval 25 | 26 | :mod:`serialize` 27 | ---------------- 28 | 29 | .. automodule:: bitcoin.core.serialize 30 | 31 | -------------------------------------------------------------------------------- /doc/bitcoin.rst: -------------------------------------------------------------------------------- 1 | bitcoin 2 | ======= 3 | 4 | :mod:`bitcoin` 5 | -------------- 6 | 7 | .. automodule:: bitcoin 8 | 9 | :mod:`base58` 10 | ------------- 11 | 12 | .. automodule:: bitcoin.base58 13 | 14 | :mod:`bloom` 15 | ------------ 16 | 17 | .. automodule:: bitcoin.bloom 18 | 19 | :mod:`messages` 20 | --------------- 21 | 22 | .. automodule:: bitcoin.messages 23 | 24 | :mod:`net` 25 | ---------- 26 | 27 | .. automodule:: bitcoin.net 28 | 29 | :mod:`rpc` 30 | ---------- 31 | 32 | .. automodule:: bitcoin.rpc 33 | 34 | :mod:`signature` 35 | ---------------- 36 | 37 | .. automodule:: bitcoin.signature 38 | 39 | :mod:`signmessage` 40 | ------------------ 41 | 42 | .. automodule:: bitcoin.signmessage 43 | 44 | :mod:`wallet` 45 | ------------- 46 | 47 | .. automodule:: bitcoin.wallet 48 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # bitcoin documentation build configuration file, created by 4 | # sphinx-quickstart on Thu May 28 20:40:55 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | PROJECT = 'python-bitcoinlib' 15 | DESCRIPTION = 'The Swiss Army Knife of the Bitcoin protocol.' 16 | AUTHORS = 'The python-bitcoinlib developers' 17 | 18 | import sphinx 19 | import sys 20 | import os 21 | 22 | # If extensions (or modules to document with autodoc) are in another directory, 23 | # add these directories to sys.path here. If the directory is relative to the 24 | # documentation root, use os.path.abspath to make it absolute, like shown here. 25 | sys.path.insert(0, os.path.abspath('..')) 26 | 27 | from bitcoin import __version__ 28 | 29 | # Prevent loading openssl when generating API docs. Either the whole library or 30 | # the necessary elliptic curve might not be available, causing import to fail. 31 | try: 32 | from unittest.mock import MagicMock 33 | except ImportError: 34 | from mock import MagicMock 35 | sys.modules['ctypes'] = MagicMock() 36 | 37 | # -- General configuration ----------------------------------------------------- 38 | 39 | # If your documentation needs a minimal Sphinx version, state it here. 40 | #needs_sphinx = '1.0' 41 | 42 | # Add any Sphinx extension module names here, as strings. They can be extensions 43 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 44 | extensions = [ 45 | 'sphinx.ext.autodoc', 46 | 'sphinx.ext.viewcode', 47 | ] 48 | 49 | autodoc_default_flags = [ 50 | 'members', 51 | 'undoc-members', 52 | 'show-inheritance', 53 | ] 54 | 55 | # Include __init__ docstring in class level docs 56 | autoclass_content = 'both' 57 | 58 | # Add any paths that contain templates here, relative to this directory. 59 | templates_path = ['_templates'] 60 | 61 | # The suffix of source filenames. 62 | source_suffix = '.rst' 63 | 64 | # The encoding of source files. 65 | #source_encoding = 'utf-8-sig' 66 | 67 | # The master toctree document. 68 | master_doc = 'index' 69 | 70 | # General information about the project. 71 | project = PROJECT 72 | copyright = '2012-2015, ' + AUTHORS 73 | 74 | # The version info for the project you're documenting, acts as replacement for 75 | # |version| and |release|, also used in various other places throughout the 76 | # built documents. 77 | # 78 | # The short X.Y version. 79 | version = __version__ 80 | # The full version, including alpha/beta/rc tags. 81 | release = __version__ 82 | 83 | # The language for content autogenerated by Sphinx. Refer to documentation 84 | # for a list of supported languages. 85 | #language = None 86 | 87 | # There are two options for replacing |today|: either, you set today to some 88 | # non-false value, then it is used: 89 | #today = '' 90 | # Else, today_fmt is used as the format for a strftime call. 91 | #today_fmt = '%B %d, %Y' 92 | 93 | # List of patterns, relative to source directory, that match files and 94 | # directories to ignore when looking for source files. 95 | exclude_patterns = ['_build'] 96 | 97 | # The reST default role (used for this markup: `text`) to use for all documents. 98 | #default_role = None 99 | 100 | # If true, '()' will be appended to :func: etc. cross-reference text. 101 | #add_function_parentheses = True 102 | 103 | # If true, the current module name will be prepended to all description 104 | # unit titles (such as .. function::). 105 | #add_module_names = True 106 | 107 | # If true, sectionauthor and moduleauthor directives will be shown in the 108 | # output. They are ignored by default. 109 | #show_authors = False 110 | 111 | # The name of the Pygments (syntax highlighting) style to use. 112 | pygments_style = 'sphinx' 113 | 114 | # A list of ignored prefixes for module index sorting. 115 | #modindex_common_prefix = [] 116 | 117 | 118 | # -- Options for HTML output --------------------------------------------------- 119 | 120 | # The theme to use for HTML and HTML Help pages. See the documentation for 121 | # a list of builtin themes. 122 | if getattr(sphinx, 'version_info', (0, 0)) >= (1, 3): 123 | html_theme = 'classic' 124 | else: 125 | html_theme = 'default' 126 | 127 | # Theme options are theme-specific and customize the look and feel of a theme 128 | # further. For a list of options available for each theme, see the 129 | # documentation. 130 | #html_theme_options = {} 131 | 132 | # Add any paths that contain custom themes here, relative to this directory. 133 | #html_theme_path = [] 134 | 135 | # The name for this set of Sphinx documents. If None, it defaults to 136 | # " v documentation". 137 | #html_title = None 138 | 139 | # A shorter title for the navigation bar. Default is the same as html_title. 140 | #html_short_title = None 141 | 142 | # The name of an image file (relative to this directory) to place at the top 143 | # of the sidebar. 144 | #html_logo = None 145 | 146 | # The name of an image file (within the static path) to use as favicon of the 147 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 148 | # pixels large. 149 | #html_favicon = None 150 | 151 | # Add any paths that contain custom static files (such as style sheets) here, 152 | # relative to this directory. They are copied after the builtin static files, 153 | # so a file named "default.css" will overwrite the builtin "default.css". 154 | html_static_path = ['_static'] 155 | 156 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 157 | # using the given strftime format. 158 | #html_last_updated_fmt = '%b %d, %Y' 159 | 160 | # If true, SmartyPants will be used to convert quotes and dashes to 161 | # typographically correct entities. 162 | #html_use_smartypants = True 163 | 164 | # Custom sidebar templates, maps document names to template names. 165 | #html_sidebars = {} 166 | 167 | # Additional templates that should be rendered to pages, maps page names to 168 | # template names. 169 | #html_additional_pages = {} 170 | 171 | # If false, no module index is generated. 172 | #html_domain_indices = True 173 | 174 | # If false, no index is generated. 175 | #html_use_index = True 176 | 177 | # If true, the index is split into individual pages for each letter. 178 | #html_split_index = False 179 | 180 | # If true, links to the reST sources are added to the pages. 181 | #html_show_sourcelink = True 182 | 183 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 184 | #html_show_sphinx = True 185 | 186 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 187 | #html_show_copyright = True 188 | 189 | # If true, an OpenSearch description file will be output, and all pages will 190 | # contain a tag referring to it. The value of this option must be the 191 | # base URL from which the finished HTML is served. 192 | #html_use_opensearch = '' 193 | 194 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 195 | #html_file_suffix = None 196 | 197 | # Output file base name for HTML help builder. 198 | htmlhelp_basename = PROJECT + 'doc' 199 | 200 | 201 | # -- Options for LaTeX output -------------------------------------------------- 202 | 203 | latex_elements = { 204 | # The paper size ('letterpaper' or 'a4paper'). 205 | #'papersize': 'letterpaper', 206 | 207 | # The font size ('10pt', '11pt' or '12pt'). 208 | #'pointsize': '10pt', 209 | 210 | # Additional stuff for the LaTeX preamble. 211 | #'preamble': '', 212 | } 213 | 214 | # Grouping the document tree into LaTeX files. List of tuples 215 | # (source start file, target name, title, author, documentclass [howto/manual]). 216 | latex_documents = [ 217 | ('index', PROJECT + '.tex', PROJECT + ' Documentation', 218 | AUTHORS, 'manual'), 219 | ] 220 | 221 | # The name of an image file (relative to this directory) to place at the top of 222 | # the title page. 223 | #latex_logo = None 224 | 225 | # For "manual" documents, if this is true, then toplevel headings are parts, 226 | # not chapters. 227 | #latex_use_parts = False 228 | 229 | # If true, show page references after internal links. 230 | #latex_show_pagerefs = False 231 | 232 | # If true, show URL addresses after external links. 233 | #latex_show_urls = False 234 | 235 | # Documents to append as an appendix to all manuals. 236 | #latex_appendices = [] 237 | 238 | # If false, no module index is generated. 239 | #latex_domain_indices = True 240 | 241 | 242 | # -- Options for manual page output -------------------------------------------- 243 | 244 | # One entry per manual page. List of tuples 245 | # (source start file, name, description, authors, manual section). 246 | man_pages = [ 247 | ('index', PROJECT, PROJECT + ' Documentation', 248 | [AUTHORS], 1) 249 | ] 250 | 251 | # If true, show URL addresses after external links. 252 | #man_show_urls = False 253 | 254 | 255 | # -- Options for Texinfo output ------------------------------------------------ 256 | 257 | # Grouping the document tree into Texinfo files. List of tuples 258 | # (source start file, target name, title, author, 259 | # dir menu entry, description, category) 260 | texinfo_documents = [ 261 | ('index', PROJECT, PROJECT + ' Documentation', 262 | AUTHORS, PROJECT, DESCRIPTION, 263 | 'Miscellaneous'), 264 | ] 265 | 266 | # Documents to append as an appendix to all manuals. 267 | #texinfo_appendices = [] 268 | 269 | # If false, no module index is generated. 270 | #texinfo_domain_indices = True 271 | 272 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 273 | #texinfo_show_urls = 'footnote' 274 | 275 | 276 | # -- Options for Epub output --------------------------------------------------- 277 | 278 | # Bibliographic Dublin Core info. 279 | epub_title = PROJECT 280 | epub_author = AUTHORS 281 | epub_publisher = AUTHORS 282 | epub_copyright = copyright 283 | 284 | # The language of the text. It defaults to the language option 285 | # or en if the language is not set. 286 | #epub_language = '' 287 | 288 | # The scheme of the identifier. Typical schemes are ISBN or URL. 289 | #epub_scheme = '' 290 | 291 | # The unique identifier of the text. This can be a ISBN number 292 | # or the project homepage. 293 | #epub_identifier = '' 294 | 295 | # A unique identification for the text. 296 | #epub_uid = '' 297 | 298 | # A tuple containing the cover image and cover page html template filenames. 299 | #epub_cover = () 300 | 301 | # HTML files that should be inserted before the pages created by sphinx. 302 | # The format is a list of tuples containing the path and title. 303 | #epub_pre_files = [] 304 | 305 | # HTML files shat should be inserted after the pages created by sphinx. 306 | # The format is a list of tuples containing the path and title. 307 | #epub_post_files = [] 308 | 309 | # A list of files that should not be packed into the epub file. 310 | #epub_exclude_files = [] 311 | 312 | # The depth of the table of contents in toc.ncx. 313 | #epub_tocdepth = 3 314 | 315 | # Allow duplicate toc entries. 316 | #epub_tocdup = True 317 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. bitcoin documentation master file, created by 2 | sphinx-quickstart on Thu May 28 20:40:55 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | python-bitcoinlib Documentation 7 | =============================== 8 | 9 | API Reference 10 | ------------- 11 | 12 | This section contains auto-generated API documentation. 13 | 14 | Contents: 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | 19 | bitcoin 20 | bitcoin.core 21 | 22 | 23 | Indices and tables 24 | ================== 25 | 26 | * :ref:`genindex` 27 | * :ref:`modindex` 28 | * :ref:`search` 29 | 30 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. linkcheck to check all external links for integrity 37 | echo. doctest to run all doctests embedded in the documentation if enabled 38 | goto end 39 | ) 40 | 41 | if "%1" == "clean" ( 42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 43 | del /q /s %BUILDDIR%\* 44 | goto end 45 | ) 46 | 47 | if "%1" == "html" ( 48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 49 | if errorlevel 1 exit /b 1 50 | echo. 51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 52 | goto end 53 | ) 54 | 55 | if "%1" == "dirhtml" ( 56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 57 | if errorlevel 1 exit /b 1 58 | echo. 59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 60 | goto end 61 | ) 62 | 63 | if "%1" == "singlehtml" ( 64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 68 | goto end 69 | ) 70 | 71 | if "%1" == "pickle" ( 72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished; now you can process the pickle files. 76 | goto end 77 | ) 78 | 79 | if "%1" == "json" ( 80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished; now you can process the JSON files. 84 | goto end 85 | ) 86 | 87 | if "%1" == "htmlhelp" ( 88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can run HTML Help Workshop with the ^ 92 | .hhp project file in %BUILDDIR%/htmlhelp. 93 | goto end 94 | ) 95 | 96 | if "%1" == "qthelp" ( 97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 98 | if errorlevel 1 exit /b 1 99 | echo. 100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 101 | .qhcp project file in %BUILDDIR%/qthelp, like this: 102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\bitcoin.qhcp 103 | echo.To view the help file: 104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\bitcoin.ghc 105 | goto end 106 | ) 107 | 108 | if "%1" == "devhelp" ( 109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished. 113 | goto end 114 | ) 115 | 116 | if "%1" == "epub" ( 117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 121 | goto end 122 | ) 123 | 124 | if "%1" == "latex" ( 125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 129 | goto end 130 | ) 131 | 132 | if "%1" == "text" ( 133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The text files are in %BUILDDIR%/text. 137 | goto end 138 | ) 139 | 140 | if "%1" == "man" ( 141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 145 | goto end 146 | ) 147 | 148 | if "%1" == "texinfo" ( 149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 153 | goto end 154 | ) 155 | 156 | if "%1" == "gettext" ( 157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 161 | goto end 162 | ) 163 | 164 | if "%1" == "changes" ( 165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.The overview file is in %BUILDDIR%/changes. 169 | goto end 170 | ) 171 | 172 | if "%1" == "linkcheck" ( 173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 174 | if errorlevel 1 exit /b 1 175 | echo. 176 | echo.Link check complete; look for any errors in the above output ^ 177 | or in %BUILDDIR%/linkcheck/output.txt. 178 | goto end 179 | ) 180 | 181 | if "%1" == "doctest" ( 182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Testing of doctests in the sources finished, look at the ^ 186 | results in %BUILDDIR%/doctest/output.txt. 187 | goto end 188 | ) 189 | 190 | :end 191 | -------------------------------------------------------------------------------- /examples/bip-0070-payment-protocol.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2013-2014 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | """Bip-0070-related functionality 15 | 16 | Creates http response objects suitable for use with 17 | bitcoin bip 70 using googles protocol buffers. 18 | """ 19 | 20 | import urllib2 21 | 22 | # https://github.com/bitcoin/bips/blob/master/bip-0070/paymentrequest.proto 23 | import payments_pb2 24 | o = payments_pb2 25 | 26 | import bitcoin 27 | #bitcoin.SelectParams('testnet') 28 | from bitcoin.wallet import CBitcoinAddress 29 | from bitcoin.core.script import CScript 30 | from bitcoin.rpc import Proxy 31 | 32 | from time import time 33 | 34 | def payment_request(): 35 | """Generates a http PaymentRequest object""" 36 | 37 | bc = Proxy() 38 | btc = bc.getnewaddress() 39 | 40 | # Setting the 'amount' field to 0 (zero) should prompt the user to enter 41 | # the amount for us but a bug in bitcoin core qt version 0.9.1 (at time of 42 | # writing) wrongly informs us that the value is too small and aborts. 43 | # https://github.com/bitcoin/bitcoin/issues/3095 44 | # Also there can be no leading 0's (zeros). 45 | btc_amount = 100000 46 | serialized_pubkey = btc.to_scriptPubKey() 47 | 48 | pdo = o.PaymentDetails() 49 | #pdo.network = 'test' 50 | pdo.outputs.add(amount = btc_amount,script = serialized_pubkey) 51 | pdo.time = int(time()) 52 | pdo.memo = 'String shown to user before confirming payment' 53 | pdo.payment_url = 'http://payment_ack.url' 54 | 55 | pro = o.PaymentRequest() 56 | pro.serialized_payment_details = pdo.SerializeToString() 57 | 58 | sds_pr = pro.SerializeToString() 59 | 60 | open('sds_pr_blob', 'wb').write(sds_pr) 61 | headers = {'Content-Type': 'application/bitcoin-payment', 62 | 'Accept': 'application/bitcoin-paymentrequest'} 63 | http_response_object = urllib2.Request('file:sds_pr_blob', None, headers) 64 | 65 | return http_response_object 66 | 67 | 68 | def payment_ack(serialized_Payment_message): 69 | """Generates a PaymentACK object, captures client refund address and returns a message""" 70 | 71 | pao = o.PaymentACK() 72 | pao.payment.ParseFromString(serialized_Payment_message) 73 | pao.memo = 'String shown to user after payment confirmation' 74 | 75 | refund_address = CBitcoinAddress.from_scriptPubKey(CScript(pao.payment.refund_to[0].script)) 76 | 77 | sds_pa = pao.SerializeToString() 78 | 79 | open('sds_pa_blob', 'wb').write(sds_pa) 80 | headers = {'Content-Type' : 'application/bitcoin-payment', 'Accept' : 'application/bitcoin-paymentack'} 81 | http_response_object = urllib2.Request('file:sds_pa_blob', None, headers) 82 | 83 | return http_response_object 84 | -------------------------------------------------------------------------------- /examples/make-bootstrap-rpc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2013-2014 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | """Make a boostrap.dat file by getting the blocks from the RPC interface.""" 15 | 16 | import bitcoin 17 | import bitcoin.rpc 18 | 19 | import struct 20 | import sys 21 | import time 22 | 23 | try: 24 | if len(sys.argv) not in (2, 3): 25 | raise Exception 26 | 27 | n = int(sys.argv[1]) 28 | 29 | if len(sys.argv) == 3: 30 | bitcoin.SelectParams(sys.argv[2]) 31 | except Exception as ex: 32 | print('Usage: %s [network=(mainnet|testnet|regtest|signet)] > bootstrap.dat' % sys.argv[0], file=sys.stderr) 33 | sys.exit(1) 34 | 35 | 36 | proxy = bitcoin.rpc.Proxy() 37 | 38 | total_bytes = 0 39 | start_time = time.time() 40 | 41 | fd = sys.stdout.buffer 42 | for i in range(n + 1): 43 | block = proxy.getblock(proxy.getblockhash(i)) 44 | 45 | block_bytes = block.serialize() 46 | 47 | total_bytes += len(block_bytes) 48 | print('%.2f KB/s, height %d, %d bytes' % 49 | ((total_bytes / 1000) / (time.time() - start_time), 50 | i, len(block_bytes)), 51 | file=sys.stderr) 52 | 53 | fd.write(bitcoin.params.MESSAGE_START) 54 | fd.write(struct.pack('= 1: 77 | logging.root.setLevel(logging.DEBUG) 78 | elif args.verbosity == -1: 79 | logging.root.setLevel(logging.WARNING) 80 | elif args.verbosity <= -2: 81 | logging.root.setLevel(logging.ERROR) 82 | 83 | if args.testnet: 84 | bitcoin.SelectParams('testnet') 85 | elif args.regtest: 86 | bitcoin.SelectParams('regtest') 87 | 88 | proxy = bitcoin.rpc.Proxy() 89 | 90 | if args.privkey is None: 91 | args.privkey = CBitcoinSecret.from_secret_bytes(os.urandom(32)) 92 | 93 | else: 94 | args.privkey = CBitcoinSecret(args.privkey) 95 | 96 | logging.info('Using keypair %s %s' % (b2x(args.privkey.pub), args.privkey)) 97 | 98 | # Turn the text file into padded lines 99 | if args.fd is sys.stdin: 100 | # work around a bug where even though we specified binary encoding we get 101 | # the sys.stdin instead. 102 | args.fd = sys.stdin.buffer 103 | raw_padded_lines = [b'\x00' + line.rstrip().ljust(args.min_len) + b'\x00' for line in args.fd.readlines()] 104 | 105 | # combine lines if < MAX_SCRIPT_ELEMENT_SIZE 106 | padded_lines = [] 107 | prev_line = b'\x00' 108 | for line in raw_padded_lines: 109 | if len(prev_line) + len(line) <= MAX_SCRIPT_ELEMENT_SIZE: 110 | prev_line = prev_line + line[1:] 111 | 112 | else: 113 | padded_lines.append(prev_line) 114 | prev_line = line 115 | 116 | if prev_line: 117 | padded_lines.append(prev_line) 118 | 119 | scripts = [] 120 | while padded_lines: 121 | def make_scripts(lines, n): 122 | # The n makes sure every p2sh addr is unique; the pubkey lets us 123 | # control the order the vin order vs. just using hashlocks. 124 | redeemScript = [] 125 | for chunk in reversed(lines): 126 | if len(chunk) > MAX_SCRIPT_ELEMENT_SIZE: 127 | parser.exit('Lines must be less than %d characters; got %d characters' %\ 128 | (MAX_SCRIPT_ELEMENT_SIZE, len(chunk))) 129 | redeemScript.extend([OP_HASH160, Hash160(chunk), OP_EQUALVERIFY]) 130 | redeemScript = CScript(redeemScript + 131 | [args.privkey.pub, OP_CHECKSIGVERIFY, 132 | n, OP_DROP, # deduplicate push dropped to meet BIP62 rules 133 | OP_DEPTH, 0, OP_EQUAL]) # prevent scriptSig malleability 134 | 135 | return CScript(lines) + redeemScript, redeemScript 136 | 137 | scriptSig = redeemScript = None 138 | for i in range(len(padded_lines)): 139 | next_scriptSig, next_redeemScript = make_scripts(padded_lines[0:i+1], len(scripts)) 140 | 141 | # FIXME: magic numbers! 142 | if len(next_redeemScript) > 520 or len(next_scriptSig) > 1600-100: 143 | padded_lines = padded_lines[i:] 144 | break 145 | 146 | else: 147 | scriptSig = next_scriptSig 148 | redeemScript = next_redeemScript 149 | 150 | else: 151 | padded_lines = [] 152 | 153 | scripts.append((scriptSig, redeemScript)) 154 | 155 | # pay to the redeemScripts to make them spendable 156 | 157 | # the 41 accounts for the size of the CTxIn itself 158 | payments = {P2SHBitcoinAddress.from_redeemScript(redeemScript):int(((len(scriptSig)+41)/1000 * args.fee_per_kb)*COIN) 159 | for scriptSig, redeemScript in scripts} 160 | 161 | prevouts_by_scriptPubKey = None 162 | if not args.dryrun: 163 | txid = proxy.sendmany('', payments, 0) 164 | 165 | logging.info('Sent pre-pub tx: %s' % b2lx(txid)) 166 | 167 | tx = proxy.getrawtransaction(txid) 168 | 169 | prevouts_by_scriptPubKey = {txout.scriptPubKey:COutPoint(txid, i) for i, txout in enumerate(tx.vout)} 170 | 171 | else: 172 | prevouts_by_scriptPubKey = {redeemScript.to_p2sh_scriptPubKey():COutPoint(b'\x00'*32, i) 173 | for i, (scriptSig, redeemScript) in enumerate(scripts)} 174 | logging.debug('Payments: %r' % payments) 175 | logging.info('Total cost: %s BTC' % str_money_value(sum(amount for addr, amount in payments.items()))) 176 | 177 | # Create unsigned tx for SignatureHash 178 | vout = [CTxOut(0, CScript([OP_RETURN]))] 179 | 180 | unsigned_vin = [] 181 | for scriptSig, redeemScript in scripts: 182 | scriptPubKey = redeemScript.to_p2sh_scriptPubKey() 183 | 184 | txin = CTxIn(prevouts_by_scriptPubKey[scriptPubKey]) 185 | unsigned_vin.append(txin) 186 | unsigned_tx = CTransaction(unsigned_vin, vout) 187 | 188 | # Sign! 189 | signed_vin = [] 190 | for i, (scriptSig, redeemScript) in enumerate(scripts): 191 | sighash = SignatureHash(redeemScript, unsigned_tx, i, SIGHASH_NONE) 192 | sig = args.privkey.sign(sighash) + bytes([SIGHASH_NONE]) 193 | 194 | signed_scriptSig = CScript([sig] + list(scriptSig)) 195 | 196 | txin = CTxIn(unsigned_vin[i].prevout, signed_scriptSig) 197 | 198 | signed_vin.append(txin) 199 | 200 | signed_tx = CTransaction(signed_vin, vout) 201 | 202 | if args.dryrun: 203 | serialized_tx = signed_tx.serialize() 204 | logging.info('tx size: %d bytes' % len(serialized_tx)) 205 | logging.debug('hex: %s' % b2x(serialized_tx)) 206 | 207 | else: 208 | # FIXME: the tx could be too long here, but there's no way to get sendmany 209 | # to *not* broadcast the transaction first. This is a proof-of-concept, so 210 | # punting. 211 | 212 | logging.debug('Sending publish tx, hex: %s' % b2x(signed_tx.serialize())) 213 | txid = proxy.sendrawtransaction(signed_tx) 214 | logging.info('Sent publish tx: %s' % b2lx(txid)) 215 | 216 | -------------------------------------------------------------------------------- /examples/send-addrs-msg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket, time, bitcoin 4 | from bitcoin.messages import msg_version, msg_verack, msg_addr 5 | from bitcoin.net import CAddress 6 | 7 | 8 | PORT = 18333 9 | 10 | bitcoin.SelectParams('testnet') 11 | 12 | def version_pkt(client_ip, server_ip): 13 | msg = msg_version() 14 | msg.nVersion = 70002 15 | msg.addrTo.ip = server_ip 16 | msg.addrTo.port = PORT 17 | msg.addrFrom.ip = client_ip 18 | msg.addrFrom.port = PORT 19 | 20 | return msg 21 | 22 | def addr_pkt( str_addrs ): 23 | msg = msg_addr() 24 | addrs = [] 25 | for i in str_addrs: 26 | addr = CAddress() 27 | addr.port = 18333 28 | addr.nTime = int(time.time()) 29 | addr.ip = i 30 | 31 | addrs.append( addr ) 32 | msg.addrs = addrs 33 | return msg 34 | 35 | s = socket.socket() 36 | 37 | server_ip = "192.168.0.149" 38 | client_ip = "192.168.0.13" 39 | 40 | s.connect( (server_ip,PORT) ) 41 | 42 | # Send Version packet 43 | s.send( version_pkt(client_ip, server_ip).to_bytes() ) 44 | 45 | # Get Version reply 46 | print(s.recv(1924)) 47 | 48 | # Send Verack 49 | s.send( msg_verack().to_bytes() ) 50 | # Get Verack 51 | print(s.recv(1024)) 52 | 53 | # Send Addrs 54 | s.send( addr_pkt(["252.11.1.2", "EEEE:7777:8888:AAAA::1"]).to_bytes() ) 55 | 56 | time.sleep(1) 57 | s.close() 58 | 59 | # debug log on the server should look like: 60 | # accepted connection 192.168.0.13:39979 61 | # send version message: version 70002, blocks=317947, us=****, them=0.0.0.0:0, peer=192.168.0.13:39979 62 | # receive version message: /pythonbitcoin0.0.1/: version 70002, blocks=-1, us=192.168.0.149:18333, them=192.168.0.13:18333, peer=192.168.0.13:39979 63 | # Added 2 addresses from 192.168.0.13: 3 tried, 1706 new 64 | # disconnecting node 192.168.0.13:39979 65 | 66 | 67 | -------------------------------------------------------------------------------- /examples/sign-message.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright (C) 2013-2015 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | from __future__ import absolute_import, division, print_function, unicode_literals 15 | 16 | from bitcoin.wallet import CBitcoinSecret, P2PKHBitcoinAddress 17 | from bitcoin.signmessage import BitcoinMessage, VerifyMessage, SignMessage 18 | 19 | def sign_message(key, msg): 20 | secret = CBitcoinSecret(key) 21 | message = BitcoinMessage(msg) 22 | return SignMessage(secret, message) 23 | 24 | def print_default(signature, key=None, msg=None): 25 | print(signature.decode('ascii')) 26 | 27 | def print_verbose(signature, key, msg): 28 | secret = CBitcoinSecret(key) 29 | address = P2PKHBitcoinAddress.from_pubkey(secret.pub) 30 | message = BitcoinMessage(msg) 31 | print('Address: %s' % address) 32 | print('Message: %s' % msg) 33 | print('Signature: %s' % signature) 34 | print('Verified: %s' % VerifyMessage(address, message, signature)) 35 | print('\nTo verify using bitcoin core:') 36 | print('\n`bitcoin-cli verifymessage %s \'%s\' \'%s\'`\n' % (address, signature.decode('ascii'), msg)) 37 | 38 | def parser(): 39 | import argparse 40 | parser = argparse.ArgumentParser( 41 | description='Sign a message with a private key.', 42 | epilog='Security warning: arguments may be visible to other users on the same host.') 43 | parser.add_argument( 44 | '-v', '--verbose', dest='print_result', 45 | action='store_const', const=print_verbose, default=print_default, 46 | help='verbose output') 47 | parser.add_argument( 48 | '-k', '--key', 49 | required=True, 50 | help='private key in base58 encoding') 51 | parser.add_argument( 52 | '-m', '--msg', 53 | required=True, 54 | help='message to sign') 55 | return parser 56 | 57 | if __name__ == '__main__': 58 | args = parser().parse_args() 59 | try: 60 | signature = sign_message(args.key, args.msg) 61 | except Exception as error: 62 | print('%s: %s' % (error.__class__.__name__, str(error))) 63 | exit(1) 64 | else: 65 | args.print_result(signature, args.key, args.msg) 66 | -------------------------------------------------------------------------------- /examples/spend-p2pkh-txout.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2014 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | """Low-level example of how to spend a standard pay-to-pubkey-hash (P2PKH) txout""" 15 | 16 | import hashlib 17 | 18 | from bitcoin import SelectParams 19 | from bitcoin.core import b2x, lx, COIN, COutPoint, CMutableTxOut, CMutableTxIn, CMutableTransaction, Hash160 20 | from bitcoin.core.script import CScript, OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL 21 | from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH 22 | from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret 23 | 24 | SelectParams('mainnet') 25 | 26 | # Create the (in)famous correct brainwallet secret key. 27 | h = hashlib.sha256(b'correct horse battery staple').digest() 28 | seckey = CBitcoinSecret.from_secret_bytes(h) 29 | 30 | # Same as the txid:vout the createrawtransaction RPC call requires 31 | # 32 | # lx() takes *little-endian* hex and converts it to bytes; in Bitcoin 33 | # transaction hashes are shown little-endian rather than the usual big-endian. 34 | # There's also a corresponding x() convenience function that takes big-endian 35 | # hex and converts it to bytes. 36 | txid = lx('7e195aa3de827814f172c362fcf838d92ba10e3f9fdd9c3ecaf79522b311b22d') 37 | vout = 0 38 | 39 | # Create the txin structure, which includes the outpoint. The scriptSig 40 | # defaults to being empty. 41 | txin = CMutableTxIn(COutPoint(txid, vout)) 42 | 43 | # We also need the scriptPubKey of the output we're spending because 44 | # SignatureHash() replaces the transaction scriptSig's with it. 45 | # 46 | # Here we'll create that scriptPubKey from scratch using the pubkey that 47 | # corresponds to the secret key we generated above. 48 | txin_scriptPubKey = CScript([OP_DUP, OP_HASH160, Hash160(seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG]) 49 | 50 | # Create the txout. This time we create the scriptPubKey from a Bitcoin 51 | # address. 52 | txout = CMutableTxOut(0.001*COIN, CBitcoinAddress('1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8').to_scriptPubKey()) 53 | 54 | # Create the unsigned transaction. 55 | tx = CMutableTransaction([txin], [txout]) 56 | 57 | # Calculate the signature hash for that transaction. 58 | sighash = SignatureHash(txin_scriptPubKey, tx, 0, SIGHASH_ALL) 59 | 60 | # Now sign it. We have to append the type of signature we want to the end, in 61 | # this case the usual SIGHASH_ALL. 62 | sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) 63 | 64 | # Set the scriptSig of our transaction input appropriately. 65 | txin.scriptSig = CScript([sig, seckey.pub]) 66 | 67 | # Verify the signature worked. This calls EvalScript() and actually executes 68 | # the opcodes in the scripts to see if everything worked out. If it doesn't an 69 | # exception will be raised. 70 | VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) 71 | 72 | # Done! Print the transaction to standard output with the bytes-to-hex 73 | # function. 74 | print(b2x(tx.serialize())) 75 | -------------------------------------------------------------------------------- /examples/spend-p2sh-txout.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2014 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | """Low-level example of how to spend a P2SH/BIP16 txout""" 15 | 16 | import hashlib 17 | 18 | from bitcoin import SelectParams 19 | from bitcoin.core import b2x, lx, COIN, COutPoint, CMutableTxOut, CMutableTxIn, CMutableTransaction, Hash160 20 | from bitcoin.core.script import CScript, OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL 21 | from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH 22 | from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret 23 | 24 | SelectParams('mainnet') 25 | 26 | # Create the (in)famous correct brainwallet secret key. 27 | h = hashlib.sha256(b'correct horse battery staple').digest() 28 | seckey = CBitcoinSecret.from_secret_bytes(h) 29 | 30 | # Create a redeemScript. Similar to a scriptPubKey the redeemScript must be 31 | # satisfied for the funds to be spent. 32 | txin_redeemScript = CScript([seckey.pub, OP_CHECKSIG]) 33 | print(b2x(txin_redeemScript)) 34 | 35 | # Create the magic P2SH scriptPubKey format from that redeemScript. You should 36 | # look at the CScript.to_p2sh_scriptPubKey() function in bitcoin.core.script to 37 | # understand what's happening, as well as read BIP16: 38 | # https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki 39 | txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() 40 | 41 | # Convert the P2SH scriptPubKey to a base58 Bitcoin address and print it. 42 | # You'll need to send some funds to it to create a txout to spend. 43 | txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) 44 | print('Pay to:',str(txin_p2sh_address)) 45 | 46 | # Same as the txid:vout the createrawtransaction RPC call requires 47 | # 48 | # lx() takes *little-endian* hex and converts it to bytes; in Bitcoin 49 | # transaction hashes are shown little-endian rather than the usual big-endian. 50 | # There's also a corresponding x() convenience function that takes big-endian 51 | # hex and converts it to bytes. 52 | txid = lx('bff785da9f8169f49be92fa95e31f0890c385bfb1bd24d6b94d7900057c617ae') 53 | vout = 0 54 | 55 | # Create the txin structure, which includes the outpoint. The scriptSig 56 | # defaults to being empty. 57 | txin = CMutableTxIn(COutPoint(txid, vout)) 58 | 59 | # Create the txout. This time we create the scriptPubKey from a Bitcoin 60 | # address. 61 | txout = CMutableTxOut(0.0005*COIN, CBitcoinAddress('323uf9MgLaSn9T7vDaK1cGAZ2qpvYUuqSp').to_scriptPubKey()) 62 | 63 | # Create the unsigned transaction. 64 | tx = CMutableTransaction([txin], [txout]) 65 | 66 | # Calculate the signature hash for that transaction. Note how the script we use 67 | # is the redeemScript, not the scriptPubKey. That's because when the CHECKSIG 68 | # operation happens EvalScript() will be evaluating the redeemScript, so the 69 | # corresponding SignatureHash() function will use that same script when it 70 | # replaces the scriptSig in the transaction being hashed with the script being 71 | # executed. 72 | sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL) 73 | 74 | # Now sign it. We have to append the type of signature we want to the end, in 75 | # this case the usual SIGHASH_ALL. 76 | sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) 77 | 78 | # Set the scriptSig of our transaction input appropriately. 79 | txin.scriptSig = CScript([sig, txin_redeemScript]) 80 | 81 | # Verify the signature worked. This calls EvalScript() and actually executes 82 | # the opcodes in the scripts to see if everything worked out. If it doesn't an 83 | # exception will be raised. 84 | VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) 85 | 86 | # Done! Print the transaction to standard output with the bytes-to-hex 87 | # function. 88 | print(b2x(tx.serialize())) 89 | -------------------------------------------------------------------------------- /examples/spend-p2wpkh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2020 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | """Low-level example of how to spend a P2WPKH output.""" 15 | 16 | import sys 17 | 18 | import hashlib 19 | 20 | from bitcoin import SelectParams 21 | from bitcoin.core import b2x, b2lx, lx, COIN, COutPoint, CTxOut, CTxIn, CTxInWitness, CTxWitness, CScriptWitness, CMutableTransaction, Hash160 22 | from bitcoin.core.script import CScript, OP_0, SignatureHash, SIGHASH_ALL, SIGVERSION_WITNESS_V0 23 | from bitcoin.wallet import CBitcoinSecret, P2WPKHBitcoinAddress 24 | from bitcoin.rpc import Proxy 25 | 26 | SelectParams("regtest") 27 | connection = Proxy() 28 | 29 | if connection._call("getblockchaininfo")["chain"] != "regtest": 30 | sys.stderr.write("This example is intended for regtest only.\n") 31 | sys.exit(1) 32 | 33 | 34 | # Create the (in)famous correct brainwallet secret key. 35 | h = hashlib.sha256(b'correct horse battery staple').digest() 36 | seckey = CBitcoinSecret.from_secret_bytes(h) 37 | 38 | # Create an address from that private key. 39 | public_key = seckey.pub 40 | scriptPubKey = CScript([OP_0, Hash160(public_key)]) 41 | address = P2WPKHBitcoinAddress.from_scriptPubKey(scriptPubKey) 42 | 43 | # Give the private key to bitcoind (for ismine, listunspent, etc). 44 | connection._call("importprivkey", str(seckey)) 45 | 46 | # Check if there's any funds available. 47 | unspentness = lambda: connection._call("listunspent", 6, 9999, [str(address)], True, {"minimumAmount": 1.0}) 48 | unspents = unspentness() 49 | while len(unspents) == 0: 50 | # mine some funds into the address 51 | connection._call("generatetoaddress", 110, str(address)) 52 | unspents = unspentness() 53 | 54 | # Choose the first UTXO, let's spend it! 55 | unspent_utxo_details = unspents[0] 56 | txid = unspent_utxo_details["txid"] 57 | vout = unspent_utxo_details["vout"] 58 | amount = int(float(unspent_utxo_details["amount"]) * COIN) 59 | 60 | # Calculate an amount for the upcoming new UTXO. Set a high fee to bypass 61 | # bitcoind minfee setting. 62 | amount_less_fee = int(amount - (0.01 * COIN)) 63 | 64 | # Create a destination to send the coins. 65 | destination_address = connection._call("getnewaddress", "python-bitcoinlib-example", "bech32") 66 | destination_address = P2WPKHBitcoinAddress(destination_address) 67 | target_scriptPubKey = destination_address.to_scriptPubKey() 68 | 69 | # Create the unsigned transaction. 70 | txin = CTxIn(COutPoint(lx(txid), vout)) 71 | txout = CTxOut(amount_less_fee, target_scriptPubKey) 72 | tx = CMutableTransaction([txin], [txout]) 73 | 74 | # Specify which transaction input is going to be signed for. 75 | txin_index = 0 76 | 77 | # When signing a P2WPKH transaction, use an "implicit" script that isn't 78 | # specified in the scriptPubKey or the witness. 79 | redeem_script = address.to_redeemScript() 80 | 81 | # Calculate the signature hash for the transaction. This is then signed by the 82 | # private key that controls the UTXO being spent here at this txin_index. 83 | sighash = SignatureHash(redeem_script, tx, txin_index, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) 84 | signature = seckey.sign(sighash) + bytes([SIGHASH_ALL]) 85 | 86 | # Construct a witness for this transaction input. The public key is given in 87 | # the witness so that the appropriate redeem_script can be calculated by 88 | # anyone. The original scriptPubKey had only the Hash160 hash of the public 89 | # key, not the public key itself, and the redeem script can be entirely 90 | # re-constructed if given just the public key. So the public key is added to 91 | # the witness. This is P2WPKH in bip141. 92 | witness = [signature, public_key] 93 | 94 | # Aggregate all of the witnesses together, and then assign them to the 95 | # transaction object. 96 | ctxinwitnesses = [CTxInWitness(CScriptWitness(witness))] 97 | tx.wit = CTxWitness(ctxinwitnesses) 98 | 99 | # Broadcast the transaction to the regtest network. 100 | spend_txid = connection.sendrawtransaction(tx) 101 | 102 | # Done! Print the transaction to standard output. Show the transaction 103 | # serialization in hex (instead of bytes), and render the txid. 104 | print("serialized transaction: {}".format(b2x(tx.serialize()))) 105 | print("txid: {}".format(b2lx(spend_txid))) 106 | -------------------------------------------------------------------------------- /examples/spend-p2wsh-txout.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2014 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | """Low-level example of how to spend a P2WSH/BIP141 txout""" 15 | 16 | import hashlib 17 | 18 | from bitcoin import SelectParams 19 | from bitcoin.core import b2x, lx, COIN, COutPoint, CMutableTxOut, CMutableTxIn, CMutableTransaction, CTxInWitness, CTxWitness 20 | from bitcoin.core.script import CScript, CScriptWitness, OP_0, OP_CHECKSIG, SignatureHash, SIGHASH_ALL, SIGVERSION_WITNESS_V0 21 | from bitcoin.wallet import CBitcoinSecret, CBitcoinAddress, P2WSHBitcoinAddress 22 | 23 | SelectParams('testnet') 24 | 25 | # Create the (in)famous correct brainwallet secret key. 26 | h = hashlib.sha256(b'correct horse battery staple').digest() 27 | seckey = CBitcoinSecret.from_secret_bytes(h) 28 | 29 | # Create a witnessScript and corresponding redeemScript. Similar to a scriptPubKey 30 | # the redeemScript must be satisfied for the funds to be spent. 31 | txin_redeemScript = CScript([seckey.pub, OP_CHECKSIG]) 32 | txin_scriptHash = hashlib.sha256(txin_redeemScript).digest() 33 | txin_scriptPubKey = CScript([OP_0, txin_scriptHash]) 34 | 35 | 36 | # Convert the P2WSH scriptPubKey to a base58 Bitcoin address and print it. 37 | # You'll need to send some funds to it to create a txout to spend. 38 | txin_p2wsh_address = P2WSHBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) 39 | print('Pay to:', str(txin_p2wsh_address)) 40 | 41 | # Same as the txid:vout the createrawtransaction RPC call requires 42 | # lx() takes *little-endian* hex and converts it to bytes; in Bitcoin 43 | # transaction hashes are shown little-endian rather than the usual big-endian. 44 | txid = lx('ace9dc7c987a52266e38fe8544c2d12182401341c98d151f4b394cf69aa5c3e5') 45 | vout = 0 46 | 47 | # Specify the amount send to your P2WSH address. 48 | amount = int(0.0001 * COIN) 49 | 50 | # Calculate an amount for the upcoming new UTXO. Set a high fee (5%) to bypass 51 | # bitcoind minfee setting. 52 | amount_less_fee = amount * 0.95 53 | 54 | # Create the txin structure, which includes the outpoint. The scriptSig 55 | # defaults to being empty as is necessary for spending a P2WSH output. 56 | txin = CMutableTxIn(COutPoint(txid, vout)) 57 | 58 | 59 | # Specify a destination address and create the txout. 60 | destination_address = CBitcoinAddress( 61 | '2NGZrVvZG92qGYqzTLjCAewvPZ7JE8S8VxE').to_scriptPubKey() 62 | txout = CMutableTxOut(amount_less_fee, destination_address) 63 | 64 | # Create the unsigned transaction. 65 | tx = CMutableTransaction([txin], [txout]) 66 | 67 | # Calculate the signature hash for that transaction. 68 | sighash = SignatureHash(script=txin_redeemScript, txTo=tx, inIdx=0, 69 | hashtype=SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) 70 | 71 | # Now sign it. We have to append the type of signature we want to the end, in 72 | # this case the usual SIGHASH_ALL. 73 | sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) 74 | 75 | 76 | # # Construct a witness for this P2WSH transaction and add to tx. 77 | witness = CScriptWitness([sig, txin_redeemScript]) 78 | tx.wit = CTxWitness([CTxInWitness(witness)]) 79 | 80 | # TODO: upgrade VerifyScript to support Segregated Witness and place verify the witness program here. 81 | 82 | # Done! Print the transaction to standard output with the bytes-to-hex 83 | # function. 84 | print(b2x(tx.serialize())) 85 | 86 | -------------------------------------------------------------------------------- /examples/ssl-rpc-connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2014 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | 15 | ## Instructions 16 | 17 | # This sets up SSL on a localhost connection. Not terribly useful but it will be iterated on. 18 | 19 | # Linux: cd ~/.bitcoin 20 | # Mac: cd ~/Library/Application\ Support/Bitcoin/ 21 | # openssl genrsa -out server.pem 2048 22 | # openssl req -new -x509 -nodes -sha256 -days 3650 -key server.pem > server.cert 23 | # The prompts are optional, you can just hit enter 24 | 25 | # Verify that your bitcoin.conf exists in the above directory and contains the following lines: 26 | # server=1 27 | # rpcssl=1 28 | # rpcuser=CHANGETHIS 29 | # rpcpassword=CHANGETHAT 30 | # rpcsslciphers=TLSv1_2 31 | # rpcsslprivatekeyfile=server.pem 32 | # rpcsslcertificatechainfile=server.cert 33 | 34 | import bitcoin.rpc 35 | 36 | proxy_connection = bitcoin.rpc.Proxy() 37 | print(proxy_connection.getnewaddress()) 38 | -------------------------------------------------------------------------------- /examples/timestamp-op-ret.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (C) 2014 The python-bitcoinlib developers 4 | # 5 | # This file is part of python-bitcoinlib. 6 | # 7 | # It is subject to the license terms in the LICENSE file found in the top-level 8 | # directory of this distribution. 9 | # 10 | # No part of python-bitcoinlib, including this file, may be copied, modified, 11 | # propagated, or distributed except according to the terms contained in the 12 | # LICENSE file. 13 | 14 | """Example of timestamping a file via OP_RETURN""" 15 | 16 | import bitcoin.rpc 17 | import sys 18 | 19 | from bitcoin import params 20 | from bitcoin.core import * 21 | from bitcoin.core.script import * 22 | 23 | proxy = bitcoin.rpc.Proxy() 24 | 25 | assert len(sys.argv) > 1 26 | 27 | digests = [] 28 | for f in sys.argv[1:]: 29 | try: 30 | with open(f, 'rb') as fd: 31 | digests.append(Hash(fd.read())) 32 | except FileNotFoundError as exp: 33 | if len(f)/2 in (20, 32): 34 | digests.append(x(f)) 35 | else: 36 | raise exp 37 | except IOError as exp: 38 | print(exp, file=sys.stderr) 39 | continue 40 | 41 | for digest in digests: 42 | txouts = [] 43 | 44 | unspent = sorted(proxy.listunspent(0), key=lambda x: hash(x['amount'])) 45 | 46 | txins = [CTxIn(unspent[-1]['outpoint'])] 47 | value_in = unspent[-1]['amount'] 48 | 49 | change_addr = proxy.getnewaddress() 50 | change_pubkey = proxy.validateaddress(change_addr)['pubkey'] 51 | change_out = CMutableTxOut(params.MAX_MONEY, CScript([change_pubkey, OP_CHECKSIG])) 52 | 53 | digest_outs = [CMutableTxOut(0, CScript([OP_RETURN, digest]))] 54 | 55 | txouts = [change_out] + digest_outs 56 | 57 | tx = CMutableTransaction(txins, txouts) 58 | 59 | 60 | FEE_PER_BYTE = 0.00025*COIN/1000 61 | while True: 62 | tx.vout[0].nValue = int(value_in - max(len(tx.serialize()) * FEE_PER_BYTE, 0.00011*COIN)) 63 | 64 | r = proxy.signrawtransaction(tx) 65 | assert r['complete'] 66 | tx = r['tx'] 67 | 68 | if value_in - tx.vout[0].nValue >= len(tx.serialize()) * FEE_PER_BYTE: 69 | print(b2x(tx.serialize())) 70 | print(len(tx.serialize()), 'bytes', file=sys.stderr) 71 | print(b2lx(proxy.sendrawtransaction(tx))) 72 | break 73 | -------------------------------------------------------------------------------- /release-notes.md: -------------------------------------------------------------------------------- 1 | # python-bitcoinlib release notes 2 | 3 | ## v0.12.2 4 | 5 | * Fixed RPC cookie location for testnet 6 | 7 | ## v0.12.1 8 | 9 | * Added `calc_weight()` method. 10 | * (Hopefully) resolved failure to find `libeay32` on Windows. 11 | 12 | ## v0.12.0 13 | 14 | * `CECKey` now rejects secrets that aren't exactly 32 bytes 15 | * Now compatible with OpenSSL v3; broke compatibility with certain script edge 16 | cases around malformed signatures. This is acceptable because 17 | python-bitcoinlib doesn't claim to have consensus compatibility and no-one 18 | should use it for script/tx validation. 19 | 20 | ## v0.11.2 21 | 22 | * Fixed one remaining use of OpenSSL for RIPEMD-160 23 | 24 | ## v0.11.1 25 | 26 | * Pure-python RIPEMD-160, for newer versions of OpenSSL without RIPEMD-160 27 | support. 28 | * Signet support 29 | 30 | ## v0.11.0 31 | 32 | * Bech32 implementation 33 | * Segwit implementation (for P2WSH and P2WPKH transactions) and examples 34 | * Use libsecp256k1 for signing 35 | * Implement OP_CHECKSEQUENCEVERIFY 36 | 37 | New maintainer: Bryan Bishop 38 | 39 | ## v0.10.2 40 | 41 | Note: this will be the last release of python-bitcoinlib with Python 2.7 42 | compatibility. 43 | 44 | * New RPC `generatetoaddress(self,numblocks,addr)`. 45 | * Fixed Python 2.7 incompatibility. 46 | * Various OpenSSL fixes, including a memory leak. 47 | 48 | 49 | ## v0.10.1 50 | 51 | Identical in every way to v0.10.0, but re-uploaded under a new version to fix a 52 | PyPi issue. 53 | 54 | 55 | ## v0.10.0 56 | 57 | Minor breaking change: RPC port for regtest updated to the new v0.16.0 default. 58 | 59 | Other changes: 60 | 61 | * Now looks for `.cookie` files in the datadir, if specified. 62 | * Authentication in a RPC `service_url` is now parsed. 63 | * Implemented bip-0037 version message. 64 | * `contrib/verify-commits/` removed for now due to breakage. 65 | 66 | 67 | ## v0.9.0 68 | 69 | Now supports segwit, which breaks the API in minor ways from v0.8.0. This 70 | version introduces lots of new API functionality related to this, such as the 71 | new `CScriptWitness`, `CTxInWitness`, `CTxWitness`, new segwit-specific logic 72 | in `SignatureHash()` etc. 73 | 74 | 75 | ## v0.8.0 76 | 77 | Major breaking API change! 78 | 79 | While this interim release doesn't by itself include segwit support, it does 80 | change the name of the `CTransaction/CMutableTransaction` method `GetHash()` to 81 | `GetTxid()` to prepare for a future segwit-enabled release. Incorrect calls to 82 | `GetHash()` will now raise a `AttributeError` exception with an explanation. 83 | 84 | Since this release doesn't yet include segwit support, you will need to set the 85 | Bitcoin Core `-rpcserialversion=0` option, either as a command line argument, 86 | or in your `bitcoin.conf` file. Otherwise the RPC interface will return 87 | segwit-serialized transactions that this release's RPC support doesn't 88 | understand. 89 | 90 | Other changes: 91 | 92 | * Cookie file RPC authentication is now supported. 93 | * `msg_header` now correctly uses `CBlockHeader` rather than `CBlock`. 94 | * RPC `getbalance` now supports `include_watchonly` 95 | * RPC `unlockwallet` is now supported 96 | 97 | 98 | ## v0.7.0 99 | 100 | Breaking API changes: 101 | 102 | * The 'cooked' CScript iterator now returns `OP_0` for the empty binary string 103 | rather than `b''` 104 | 105 | * The alias `JSONRPCException = JSONRPCError` has been removed. This alias was 106 | added for compatibility with v0.4.0 of python-bitcoinlib. 107 | 108 | * Where appropriate, `RPC_INVALID_ADDRESS_OR_KEY` errors are now caught 109 | properly, which means that rather than raising `IndexError`, RPC commands 110 | such as `getblock` may raise `JSONRPCError` instead. For instance during 111 | initial startup previously python-bitcoinlib would incorrectly raise 112 | `IndexError` rather than letting the callee know that RPC was unusable. Along 113 | those lines, `JSONRPCError` subclasses have been added for some (but not 114 | all!) of the types of RPC errors Bitcoin Core returns. 115 | 116 | Bugfixes: 117 | 118 | * Fixed a spurious `AttributeError` when `bitcoin.rpc.Proxy()` fails. 119 | 120 | 121 | ## v0.6.1 122 | 123 | New features: 124 | 125 | * getblockheader RPC call now supports the verbose option; there's no other way 126 | to get the block height, among other things, from the RPC interface. 127 | * subtoaddress and sendmany RPC calls now support comment and 128 | subtractfeefromamount arguments. 129 | 130 | 131 | ## v0.6.0 132 | 133 | Breaking API changes: 134 | 135 | * RPC over SSL support removed to match Bitcoin Core's removal of RPC SSL 136 | support in v0.12.0 If you need this, use an alternative such as a stunnel or 137 | a SSH tunnel. 138 | 139 | * Removed SCRIPT_VERIFY constants ``bitcoin.core.script``, leaving just the 140 | constants in ``bitcoin.core.scripteval``; being singletons the redundant 141 | constants were broken anyway. 142 | 143 | * SCRIPT_VERIFY_EVEN_S renamed to SCRIPT_VERIFY_LOW_S to match Bitcoin Core's naming 144 | 145 | * SCRIPT_VERIFY_NOCACHE removed as Bitcoin Core no longer has it (and we never 146 | did anything with it anyway) 147 | 148 | 149 | ## v0.5.1 150 | 151 | Various small bugfixes; see git history. 152 | 153 | New features: 154 | 155 | * New RPC calls: fundrawtransaction, generate, getblockheader 156 | * OP_CHECKLOCKTIMEVERIFY opcode constant 157 | 158 | 159 | ## v0.5.0 160 | 161 | Major fix: Fixed OpenSSL related crashes on OSX and Arch Linux. Big thanks to 162 | everyone who helped fix this! 163 | 164 | Breaking API changes: 165 | 166 | * Proxy no longer has ``__getattr__`` to support arbitrary methods. Use 167 | RawProxy or Proxy.call instead. This allows new wrappers to be added safely. 168 | See docstrings for details. 169 | 170 | New features: 171 | 172 | * New RPC calls: getbestblockhash, getblockcount, getmininginfo 173 | * Signing and verification of Bitcoin Core compatible messages. (w/ pubkey recovery) 174 | * Tox tests 175 | * Sphinx docs 176 | 177 | Notable bugfixes: 178 | 179 | * getinfo() now works where disablewallet=1 180 | 181 | 182 | ## v0.4.0 183 | 184 | Major fix: OpenSSL 1.0.1k rejects non-canonical DER signatures, which Bitcoin 185 | Core does not, so we now canonicalize signatures prior to passing them to 186 | OpenSSL. Secondly we now only generate low-S DER signatures as per BIP62. 187 | 188 | API changes that might break compatibility with existing code: 189 | 190 | * MAX_MONEY is now a core chain parameter 191 | * MainParams now inherits from CoreMainParams rather than CoreChainParams 192 | * str() now returns hash:n format; previously was same as repr() 193 | * RawProxy() no longer has _connection parameter 194 | 195 | Notable bugfixes: 196 | 197 | * MsgSerializable.to_bytes() no longer clobbers testnet params 198 | * HTTPS RPC connections now use port 443 as default 199 | * No longer assumes bitcoin.conf specifes rpcuser 200 | 201 | New features: 202 | 203 | * New RPC calls: dumpprivkey, importaddress 204 | * Added P2P support for msg_notfound and msg_reject 205 | * Added support for IPv6 addr messages 206 | 207 | 208 | ## v0.3.0 209 | 210 | Major change: cleaned up what symbols are exported by modules. \_\_all\_\_ is now 211 | used extensively, which may break some applications that were not importing the 212 | right modules. Along those lines some implementation details like the ssl 213 | attribute of the bitcoin.core.key module, and the entire bitcoin.core.bignum 214 | module, are no longer part of the public API. This should not affect too many 215 | users, but it will break some code. 216 | 217 | Other notable changes: 218 | 219 | * New getreceivedbyaddress RPC call. 220 | * Fixed getbalance RPC call when wallet is configured off. 221 | * Various code cleanups and minor bug fixes. 222 | 223 | 224 | ## v0.2.1 225 | 226 | * Improve bitcoin address handling. P2SH and P2PKH addresses now get their own 227 | classes - P2SHBitcoinAddress and P2PKHBitcoinAddress respectively - and P2PKH 228 | can now convert scriptPubKeys containing non-canonical pushes as well as bare 229 | checksig to addresses. 230 | * .deserialize() methods now fail if there is extra data left over. 231 | * Various other small bugfixes. 232 | * License is now LGPL v3 or later. 233 | 234 | 235 | ## v0.2.0 236 | 237 | Major change: CTransaction, CBlock, etc. now come in immutable (default) and 238 | mutable forms. In most cases mutable and immutable can be used interchangeably; 239 | when that is not possible methods are provided to create new (im)mutable 240 | objects from (im)mutable ones efficiently. 241 | 242 | Other changes: 243 | 244 | * New BIP70 payment protocol example. (Derren Desouza) 245 | * Rework of message serialization. Note that this may not represent the final 246 | form of P2P support, which is still in flux. (Florian Schmaus) 247 | * Various bugfixes 248 | 249 | Finally starting this release, git tags will be of the form 250 | 'python-bitcoinlib-(version)', replacing the less specific '(version)' form 251 | previously used. 252 | 253 | -------------------------------------------------------------------------------- /runtests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | #-*-mode: sh; encoding: utf-8-*- 3 | 4 | _MY_DIR="$( cd "$( dirname "${0}" )" && pwd )" 5 | set -ex 6 | [ -d "${_MY_DIR}" ] 7 | [ "${_MY_DIR}/runtests.sh" -ef "${0}" ] 8 | cd "${_MY_DIR}" 9 | exec tox ${1+"${@}"} 10 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from setuptools import setup, find_packages 4 | import os 5 | 6 | from bitcoin import __version__ 7 | 8 | here = os.path.abspath(os.path.dirname(__file__)) 9 | with open(os.path.join(here, 'README.md')) as f: 10 | README = f.read() 11 | 12 | requires = [] 13 | 14 | setup(name='python-bitcoinlib', 15 | version=__version__, 16 | description='The Swiss Army Knife of the Bitcoin protocol.', 17 | long_description=README, 18 | long_description_content_type='text/markdown', 19 | classifiers=[ 20 | "Programming Language :: Python", 21 | "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", 22 | ], 23 | url='https://github.com/petertodd/python-bitcoinlib', 24 | keywords='bitcoin', 25 | packages=find_packages(), 26 | zip_safe=False, 27 | install_requires=requires, 28 | test_suite="bitcoin.tests" 29 | ) 30 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | #-*-mode: ini; encoding: utf-8-*- 2 | 3 | [tox] #------------------------------------------------------------------- 4 | 5 | envlist = reset,py34,py35,py36,py37,py38,py39,pypy3,stats 6 | skip_missing_interpreters = True 7 | 8 | [testenv] #--------------------------------------------------------------- 9 | 10 | commands = 11 | coverage run --append --omit='tests/*,*/site-packages/*,*/distutils/*,*/lib_pypy/*' setup.py test -q 12 | 13 | deps = 14 | coverage 15 | 16 | setenv = 17 | PYTHONWARNINGS = all 18 | 19 | [testenv:reset] #--------------------------------------------------------- 20 | 21 | commands = 22 | coverage erase 23 | 24 | [testenv:stats] #--------------------------------------------------------- 25 | 26 | commands = 27 | coverage report 28 | coverage html 29 | --------------------------------------------------------------------------------