├── .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 |
--------------------------------------------------------------------------------