├── .gitignore ├── README ├── BUGS ├── bitcoin ├── __init__.py ├── tests │ ├── __init__.py │ ├── data │ │ └── base58_encode_decode.json │ ├── test_base58.py │ ├── test_hash.py │ └── test_bloom.py ├── hash.py ├── coredefs.py ├── bignum.py ├── base58.py ├── bloom.py ├── key.py ├── serialize.py ├── rpc.py ├── messages.py ├── script.py ├── core.py └── scripteval.py ├── TODO └── COPYING /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | 4 | local*.cfg 5 | 6 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Peter Todd has taken over maintainership of python-bitcoinlib. Please use the 2 | new repository at: 3 | 4 | https://github.com/petertodd/python-bitcoinlib 5 | 6 | -------------------------------------------------------------------------------- /BUGS: -------------------------------------------------------------------------------- 1 | 2 | - Appears to have difficulty talking to nodes with protocol versions 3 | between 40000 and 50001, inclusive. 4 | 5 | - Truncated or corrupted serialization may crash the program... 6 | must test and see which exceptions are thrown. 7 | 8 | -------------------------------------------------------------------------------- /bitcoin/__init__.py: -------------------------------------------------------------------------------- 1 | # Distributed under the MIT/X11 software license, see the accompanying 2 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 3 | 4 | from __future__ import absolute_import, division, print_function, unicode_literals 5 | -------------------------------------------------------------------------------- /bitcoin/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Distributed under the MIT/X11 software license, see the accompanying 2 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 3 | 4 | from __future__ import absolute_import, division, print_function, unicode_literals 5 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | See BUGS for other info. 3 | 4 | pay to script hash (P2SH, BIP 16) 5 | 6 | script opcodes: 7 | OP_2ROT 8 | 9 | P2P commands: 10 | alert 11 | 12 | Evaluate this checklist: 13 | https://en.bitcoin.it/wiki/Protocol_rules#.22block.22_messages 14 | 15 | -------------------------------------------------------------------------------- /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/test_base58.py: -------------------------------------------------------------------------------- 1 | # Distributed under the MIT/X11 software license, see the accompanying 2 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 3 | 4 | from __future__ import absolute_import, division, print_function, unicode_literals 5 | 6 | import json 7 | import os 8 | import unittest 9 | 10 | from binascii import unhexlify 11 | 12 | from bitcoin.base58 import * 13 | 14 | 15 | def load_test_vector(name): 16 | with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: 17 | for testcase in json.load(fd): 18 | yield testcase 19 | 20 | class Test_base58(unittest.TestCase): 21 | def test_encode_decode(self): 22 | for exp_bin, exp_base58 in load_test_vector('base58_encode_decode.json'): 23 | exp_bin = unhexlify(exp_bin.encode('utf8')) 24 | 25 | act_base58 = encode(exp_bin) 26 | act_bin = decode(exp_base58) 27 | 28 | self.assertEqual(act_base58, exp_base58) 29 | self.assertEqual(act_bin, exp_bin) 30 | 31 | def test_invalid_base58_exception(self): 32 | with self.assertRaises(InvalidBase58Error): 33 | decode('#') 34 | 35 | # FIXME: need to test CBitcoinAddress 36 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | With the exception of bitcoin/rpc.py, which is licensed under the GNU LGPL, the 2 | following license terms apply to the package python-bitcoinlib unless otherwise 3 | noted: 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /bitcoin/tests/test_hash.py: -------------------------------------------------------------------------------- 1 | # Distributed under the MIT/X11 software license, see the accompanying 2 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 3 | 4 | from __future__ import absolute_import, division, print_function, unicode_literals 5 | 6 | import json 7 | import os 8 | import unittest 9 | 10 | from binascii import unhexlify 11 | 12 | from bitcoin.hash import * 13 | 14 | class Test_MurmurHash3(unittest.TestCase): 15 | def test(self): 16 | def T(expected, seed, data): 17 | self.assertEqual(MurmurHash3(seed, unhexlify(data)), expected) 18 | 19 | T(0x00000000, 0x00000000, b""); 20 | T(0x6a396f08, 0xFBA4C795, b""); 21 | T(0x81f16f39, 0xffffffff, b""); 22 | 23 | T(0x514e28b7, 0x00000000, b"00"); 24 | T(0xea3f0b17, 0xFBA4C795, b"00"); 25 | T(0xfd6cf10d, 0x00000000, b"ff"); 26 | 27 | T(0x16c6b7ab, 0x00000000, b"0011"); 28 | T(0x8eb51c3d, 0x00000000, b"001122"); 29 | T(0xb4471bf8, 0x00000000, b"00112233"); 30 | T(0xe2301fa8, 0x00000000, b"0011223344"); 31 | T(0xfc2e4a15, 0x00000000, b"001122334455"); 32 | T(0xb074502c, 0x00000000, b"00112233445566"); 33 | T(0x8034d2a0, 0x00000000, b"0011223344556677"); 34 | T(0xb4698def, 0x00000000, b"001122334455667788"); 35 | -------------------------------------------------------------------------------- /bitcoin/hash.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # hash.py 4 | # 5 | # Distributed under the MIT/X11 software license, see the accompanying 6 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 7 | # 8 | 9 | from __future__ import absolute_import, division, print_function, unicode_literals 10 | 11 | import struct 12 | from bitcoin.serialize import * 13 | from bitcoin.coredefs import * 14 | from bitcoin.script import CScript 15 | 16 | def ROTL32(x, r): 17 | assert x <= 0xFFFFFFFF 18 | return ((x << r) & 0xFFFFFFFF) | (x >> (32 - r)) 19 | 20 | def MurmurHash3(nHashSeed, vDataToHash): 21 | """MurmurHash3 (x86_32) 22 | 23 | Used for bloom filters. See http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp 24 | """ 25 | 26 | assert nHashSeed <= 0xFFFFFFFF 27 | 28 | h1 = nHashSeed 29 | c1 = 0xcc9e2d51 30 | c2 = 0x1b873593 31 | 32 | # body 33 | i = 0 34 | while i < len(vDataToHash) - len(vDataToHash) % 4 \ 35 | and len(vDataToHash) - i >= 4: 36 | 37 | k1 = struct.unpack(b" '3': 55 | # In Py3 indexing bytes returns numbers, not characters 56 | bord = lambda x: x 57 | if len(vDataToHash) & 3 >= 3: 58 | k1 ^= bord(vDataToHash[j+2]) << 16 59 | if len(vDataToHash) & 3 >= 2: 60 | k1 ^= bord(vDataToHash[j+1]) << 8 61 | if len(vDataToHash) & 3 >= 1: 62 | k1 ^= bord(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 | -------------------------------------------------------------------------------- /bitcoin/coredefs.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # coredefs.py 4 | # 5 | # Distributed under the MIT/X11 software license, see the accompanying 6 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 7 | # 8 | 9 | from __future__ import absolute_import, division, print_function, unicode_literals 10 | 11 | PROTO_VERSION = 60002 12 | 13 | CADDR_TIME_VERSION = 31402 14 | 15 | MIN_PROTO_VERSION = 209 16 | 17 | BIP0031_VERSION = 60000 18 | 19 | NOBLKS_VERSION_START = 32000 20 | NOBLKS_VERSION_END = 32400 21 | 22 | MEMPOOL_GD_VERSION = 60002 23 | 24 | COIN = 100000000 25 | MAX_MONEY = 21000000 * COIN 26 | 27 | def MoneyRange(nValue): 28 | return 0<= nValue <= MAX_MONEY 29 | 30 | class NetMagic(object): 31 | def __init__(self, msg_start, block0, checkpoints): 32 | self.msg_start = msg_start 33 | self.block0 = block0 34 | self.checkpoints = checkpoints 35 | 36 | self.checkpoint_max = 0 37 | for height in self.checkpoints.keys(): 38 | if height > self.checkpoint_max: 39 | self.checkpoint_max = height 40 | 41 | NETWORKS = { 42 | 'mainnet' : NetMagic(b"\xf9\xbe\xb4\xd9", 43 | 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f, 44 | { 45 | 0: 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f, 46 | 11111: 0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d, 47 | 33333: 0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6, 48 | 74000: 0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20, 49 | 105000: 0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97, 50 | 134444: 0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe, 51 | 168000: 0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763, 52 | 193000: 0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317, 53 | 210000: 0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e, 54 | 216116: 0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e, 55 | }), 56 | 'testnet3' : NetMagic(b"\x0b\x11\x09\x07", 57 | 0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943, 58 | { 59 | 0: 0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943, 60 | }) 61 | } 62 | 63 | -------------------------------------------------------------------------------- /bitcoin/bignum.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # bignum.py 4 | # 5 | # Distributed under the MIT/X11 software license, see the accompanying 6 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 7 | # 8 | 9 | from __future__ import absolute_import, division, print_function, unicode_literals 10 | 11 | import struct 12 | 13 | 14 | # generic big endian MPI format 15 | 16 | def bn_bytes(v, have_ext=False): 17 | ext = 0 18 | if have_ext: 19 | ext = 1 20 | return ((v.bit_length()+7)//8) + ext 21 | 22 | def bn2bin(v): 23 | s = bytearray() 24 | i = bn_bytes(v) 25 | while i > 0: 26 | s.append((v >> ((i-1) * 8)) & 0xff) 27 | i -= 1 28 | return s 29 | 30 | def bin2bn(s): 31 | l = 0 32 | for ch in s: 33 | l = (l << 8) | ch 34 | return l 35 | 36 | def bn2mpi(v): 37 | have_ext = False 38 | if v.bit_length() > 0: 39 | have_ext = (v.bit_length() & 0x07) == 0 40 | 41 | neg = False 42 | if v < 0: 43 | neg = True 44 | v = -v 45 | 46 | s = struct.pack(b">I", bn_bytes(v, have_ext)) 47 | ext = bytearray() 48 | if have_ext: 49 | ext.append(0) 50 | v_bin = bn2bin(v) 51 | if neg: 52 | if have_ext: 53 | ext[0] |= 0x80 54 | else: 55 | v_bin[0] |= 0x80 56 | return s + ext + v_bin 57 | 58 | def mpi2bn(s): 59 | if len(s) < 4: 60 | return None 61 | s_size = str(s[:4]) 62 | v_len = struct.unpack(b">I", s_size)[0] 63 | if len(s) != (v_len + 4): 64 | return None 65 | if v_len == 0: 66 | return 0 67 | 68 | v_str = bytearray(s[4:]) 69 | neg = False 70 | i = v_str[0] 71 | if i & 0x80: 72 | neg = True 73 | i &= ~0x80 74 | v_str[0] = i 75 | 76 | v = bin2bn(v_str) 77 | 78 | if neg: 79 | return -v 80 | return v 81 | 82 | # bitcoin-specific little endian format, with implicit size 83 | def mpi2vch(s): 84 | r = s[4:] # strip size 85 | r = r[::-1] # reverse string, converting BE->LE 86 | return r 87 | 88 | def bn2vch(v): 89 | return str(mpi2vch(bn2mpi(v))) 90 | 91 | def vch2mpi(s): 92 | r = struct.pack(b">I", len(s)) # size 93 | r += s[::-1] # reverse string, converting LE->BE 94 | return r 95 | 96 | def vch2bn(s): 97 | return mpi2bn(vch2mpi(s)) 98 | 99 | -------------------------------------------------------------------------------- /bitcoin/tests/test_bloom.py: -------------------------------------------------------------------------------- 1 | # Distributed under the MIT/X11 software license, see the accompanying 2 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 3 | 4 | from __future__ import absolute_import, division, print_function, unicode_literals 5 | 6 | import json 7 | import os 8 | import unittest 9 | 10 | from binascii import unhexlify 11 | 12 | from bitcoin.bloom import * 13 | 14 | class Test_CBloomFilter(unittest.TestCase): 15 | def test_create_insert_serialize(self): 16 | filter = CBloomFilter(3, 0.01, 0, CBloomFilter.UPDATE_ALL) 17 | 18 | def T(elem): 19 | """Filter contains elem""" 20 | elem = unhexlify(elem) 21 | filter.insert(elem) 22 | self.assertTrue(filter.contains(elem)) 23 | 24 | def F(elem): 25 | """Filter does not contain elem""" 26 | elem = unhexlify(elem) 27 | self.assertFalse(filter.contains(elem)) 28 | 29 | T(b'99108ad8ed9bb6274d3980bab5a85c048f0950c8') 30 | F(b'19108ad8ed9bb6274d3980bab5a85c048f0950c8') 31 | T(b'b5a2c786d9ef4658287ced5914b37a1b4aa32eee') 32 | T(b'b9300670b4c5366e95b2699e8b18bc75e5f729c5') 33 | 34 | self.assertEqual(filter.serialize(), unhexlify(b'03614e9b050000000000000001')) 35 | 36 | def test_create_insert_serialize_with_tweak(self): 37 | # Same test as bloom_create_insert_serialize, but we add a nTweak of 100 38 | filter = CBloomFilter(3, 0.01, 2147483649, CBloomFilter.UPDATE_ALL) 39 | 40 | def T(elem): 41 | """Filter contains elem""" 42 | elem = unhexlify(elem) 43 | filter.insert(elem) 44 | self.assertTrue(filter.contains(elem)) 45 | 46 | def F(elem): 47 | """Filter does not contain elem""" 48 | elem = unhexlify(elem) 49 | self.assertFalse(filter.contains(elem)) 50 | 51 | T(b'99108ad8ed9bb6274d3980bab5a85c048f0950c8') 52 | F(b'19108ad8ed9bb6274d3980bab5a85c048f0950c8') 53 | T(b'b5a2c786d9ef4658287ced5914b37a1b4aa32eee') 54 | T(b'b9300670b4c5366e95b2699e8b18bc75e5f729c5') 55 | 56 | self.assertEqual(filter.serialize(), unhexlify(b'03ce4299050000000100008001')) 57 | 58 | def test_bloom_create_insert_key(self): 59 | filter = CBloomFilter(2, 0.001, 0, CBloomFilter.UPDATE_ALL) 60 | 61 | pubkey = unhexlify(b'045B81F0017E2091E2EDCD5EECF10D5BDD120A5514CB3EE65B8447EC18BFC4575C6D5BF415E54E03B1067934A0F0BA76B01C6B9AB227142EE1D543764B69D901E0') 62 | pubkeyhash = ser_uint160(Hash160(pubkey)) 63 | 64 | filter.insert(pubkey) 65 | filter.insert(pubkeyhash) 66 | 67 | self.assertEqual(filter.serialize(), unhexlify(b'038fc16b080000000000000001')) 68 | -------------------------------------------------------------------------------- /bitcoin/base58.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # base58.py 4 | # Original source: git://github.com/joric/brutus.git 5 | # which was forked from git://github.com/samrushing/caesure.git 6 | # 7 | # Distributed under the MIT/X11 software license, see the accompanying 8 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 9 | # 10 | 11 | from __future__ import absolute_import, division, print_function, unicode_literals 12 | 13 | from bitcoin.serialize import Hash, ser_uint256 14 | 15 | b58_digits = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 16 | 17 | from binascii import hexlify, unhexlify 18 | 19 | class Base58Error(Exception): 20 | pass 21 | 22 | class InvalidBase58Error(Base58Error): 23 | pass 24 | 25 | def encode(b): 26 | """Encode bytes to a base58-encoded string""" 27 | 28 | # Convert big-endian bytes to integer 29 | n = int('0x0' + hexlify(b).decode('utf8'), 16) 30 | 31 | # Divide that integer into bas58 32 | res = [] 33 | while n > 0: 34 | n, r = divmod (n, 58) 35 | res.append(b58_digits[r]) 36 | res = ''.join(res[::-1]) 37 | 38 | # Encode leading zeros as base58 zeros 39 | import sys 40 | czero = b'\x00' 41 | if sys.version > '3': 42 | # In Python3 indexing a bytes returns numbers, not characters. 43 | czero = 0 44 | pad = 0 45 | for c in b: 46 | if c == czero: pad += 1 47 | else: break 48 | return b58_digits[0] * pad + res 49 | 50 | def decode(s): 51 | """Decode a base58-encoding string, returning bytes""" 52 | if not s: 53 | return b'' 54 | 55 | # Convert the string to an integer 56 | n = 0 57 | for c in s: 58 | n *= 58 59 | if c not in b58_digits: 60 | raise InvalidBase58Error('Character %r is not a valid base58 character' % c) 61 | digit = b58_digits.index(c) 62 | n += digit 63 | 64 | # Convert the integer to bytes 65 | h = '%x' % n 66 | if len(h) % 2: 67 | h = '0' + h 68 | res = unhexlify(h.encode('utf8')) 69 | 70 | # Add padding back. 71 | pad = 0 72 | for c in s[:-1]: 73 | if c == b58_digits[0]: pad += 1 74 | else: break 75 | return b'\x00' * pad + res 76 | 77 | 78 | class Base58ChecksumError(Base58Error): 79 | pass 80 | 81 | class CBase58Data(bytes): 82 | def __new__(cls, data, nVersion): 83 | self = super(CBase58Data, cls).__new__(cls, data) 84 | self.nVersion = nVersion 85 | return self 86 | 87 | def __repr__(self): 88 | return '%s(%s, %d)' % (self.__class__.__name__, bytes.__repr__(self), self.nVersion) 89 | 90 | def __str__(self): 91 | vs = chr(self.nVersion) + self 92 | check = ser_uint256(Hash(vs))[0:4] 93 | return encode(vs + check) 94 | 95 | @classmethod 96 | def from_str(cls, s): 97 | k = decode(s) 98 | addrbyte, data, check0 = k[0], k[1:-4], k[-4:] 99 | check1 = ser_uint256(Hash(addrbyte + data))[:4] 100 | if check0 != check1: 101 | raise Base58ChecksumError('Checksum mismatch: expected %r, calculated %r' % (check0, check1)) 102 | return cls(data, ord(addrbyte)) 103 | 104 | 105 | class CBitcoinAddress(CBase58Data): 106 | PUBKEY_ADDRESS = 0 107 | SCRIPT_ADDRESS = 5 108 | PUBKEY_ADDRESS_TEST = 111 109 | SCRIPT_ADDRESS_TEST = 196 110 | -------------------------------------------------------------------------------- /bitcoin/bloom.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # bloom.py 4 | # 5 | # Distributed under the MIT/X11 software license, see the accompanying 6 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 7 | # 8 | 9 | from __future__ import absolute_import, division, print_function, unicode_literals 10 | 11 | import struct 12 | import math 13 | from bitcoin.serialize import * 14 | from bitcoin.coredefs import * 15 | from bitcoin.core import * 16 | from bitcoin.hash import MurmurHash3 17 | 18 | class CBloomFilter(object): 19 | # 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001% 20 | MAX_BLOOM_FILTER_SIZE = 36000 21 | MAX_HASH_FUNCS = 50 22 | 23 | UPDATE_NONE = 0 24 | UPDATE_ALL = 1 25 | UPDATE_P2PUBKEY_ONLY = 2 26 | UPDATE_MASK = 3 27 | 28 | def __init__(self, nElements, nFPRate, nTweak, nFlags): 29 | """Create a new bloom filter 30 | 31 | The filter will have a given false-positive rate when filled with the 32 | given number of elements. 33 | 34 | Note that if the given parameters will result in a filter outside the 35 | bounds of the protocol limits, the filter created will be as close to 36 | the given parameters as possible within the protocol limits. This will 37 | apply if nFPRate is very low or nElements is unreasonably high. 38 | 39 | nTweak is a constant which is added to the seed value passed to the 40 | hash function It should generally always be a random value (and is 41 | largely only exposed for unit testing) 42 | 43 | nFlags should be one of the UPDATE_* enums (but not _MASK) 44 | """ 45 | LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455 46 | LN2 = 0.6931471805599453094172321214581765680755001343602552 47 | self.vData = bytearray(int(min(-1 / LN2SQUARED * nElements * math.log(nFPRate), self.MAX_BLOOM_FILTER_SIZE * 8) / 8)) 48 | self.nHashFuncs = int(min(len(self.vData) * 8 / nElements * LN2, self.MAX_HASH_FUNCS)) 49 | self.nTweak = nTweak 50 | self.nFlags = nFlags 51 | 52 | def bloom_hash(self, nHashNum, vDataToHash): 53 | return MurmurHash3(((nHashNum * 0xFBA4C795) + self.nTweak) & 0xFFFFFFFF, vDataToHash) % (len(self.vData) * 8) 54 | 55 | __bit_mask = bytearray([0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]) 56 | def insert(self, elem): 57 | """Insert an element in the filter. 58 | 59 | elem may be a COutPoint or bytes 60 | """ 61 | if isinstance(elem, COutPoint): 62 | elem = elem.serialize() 63 | 64 | if len(self.vData) == 1 and self.vData[0] == 0xff: 65 | return 66 | 67 | for i in range(0, self.nHashFuncs): 68 | nIndex = self.bloom_hash(i, elem) 69 | # Sets bit nIndex of vData 70 | self.vData[nIndex >> 3] |= self.__bit_mask[7 & nIndex] 71 | 72 | def contains(self, elem): 73 | """Test if the filter contains an element 74 | 75 | elem may be a COutPoint or bytes 76 | """ 77 | if isinstance(elem, COutPoint): 78 | elem = elem.serialize() 79 | 80 | if len(self.vData) == 1 and self.vData[0] == 0xff: 81 | return True 82 | 83 | for i in range(0, self.nHashFuncs): 84 | nIndex = self.bloom_hash(i, elem) 85 | if not (self.vData[nIndex >> 3] & self.__bit_mask[7 & nIndex]): 86 | return False 87 | return True 88 | 89 | def IsWithinSizeConstraints(self): 90 | return len(self.vData) <= self.MAX_BLOOM_FILTER_SIZE and self.nHashFuncs <= self.MAX_HASH_FUNCS 91 | 92 | def IsRelevantAndUpdate(tx, tx_hash): 93 | # Not useful for a client, so not implemented yet. 94 | raise NotImplementedError 95 | 96 | __struct = struct.Struct(b' '3': 18 | bchr = lambda x: bytes([x]) 19 | 20 | def deser_string(f): 21 | nit = struct.unpack(b">= 32 51 | return rs 52 | 53 | def ser_uint160(u): 54 | rs = b"" 55 | for i in range(5): 56 | rs += struct.pack(b">= 32 58 | return rs 59 | 60 | def uint160_from_str(s): 61 | r = 0 62 | t = struct.unpack(b"> 24) & 0xFF 76 | v = (c & 0xFFFFFF) << (8 * (nbytes - 3)) 77 | return v 78 | 79 | def uint256_to_shortstr(u): 80 | s = "%064x" % (u,) 81 | return s[:16] 82 | 83 | def deser_vector(f, c, arg1=None): 84 | nit = struct.unpack(b" rather than > 170 | f.__name__ = name 171 | return f 172 | 173 | 174 | def _batch(self, rpc_call_list): 175 | postdata = json.dumps(list(rpc_call_list)) 176 | self.__conn.request('POST', self.__url.path, postdata, 177 | {'Host': self.__url.hostname, 178 | 'User-Agent': USER_AGENT, 179 | 'Authorization': self.__auth_header, 180 | 'Content-type': 'application/json'}) 181 | 182 | return self._get_response() 183 | 184 | def _get_response(self): 185 | http_response = self.__conn.getresponse() 186 | if http_response is None: 187 | raise JSONRPCException({ 188 | 'code': -342, 'message': 'missing HTTP response from server'}) 189 | 190 | return json.loads(http_response.read().decode('utf8'), 191 | parse_float=decimal.Decimal) 192 | 193 | 194 | class Proxy(RawProxy): 195 | def __init__(self, service_url=None, 196 | service_port=8332, 197 | btc_conf_file=None, 198 | timeout=HTTP_TIMEOUT, 199 | **kwargs): 200 | """Create a proxy to a bitcoin RPC service 201 | 202 | Unlike RawProxy data is passed as objects, rather than JSON. (not yet 203 | fully implemented) 204 | 205 | If service_url is not specified the username and password are read out 206 | of the file btc_conf_file. If btc_conf_file is not specified 207 | ~/.bitcoin/bitcoin.conf or equivalent is used by default. 208 | 209 | Usually no arguments to Proxy() are needed; the local bitcoind will be 210 | used. 211 | 212 | timeout - timeout in seconds before the HTTP interface times out 213 | """ 214 | super(Proxy, self).__init__(service_url=service_url, service_port=service_port, btc_conf_file=btc_conf_file, 215 | timeout=HTTP_TIMEOUT, 216 | **kwargs) 217 | 218 | def getinfo(self): 219 | """Returns an object containing various state info""" 220 | r = self._call('getinfo') 221 | r['balance'] = int(r['balance'] * COIN) 222 | r['paytxfee'] = int(r['paytxfee'] * COIN) 223 | return r 224 | 225 | def getnewaddress(self, account=None): 226 | """Return a new Bitcoin address for receiving payments. 227 | 228 | If account is not None, it is added to the address book so payments 229 | received with the address will be credited to account. 230 | """ 231 | r = None 232 | if account is not None: 233 | r = self._call('getnewaddress', account) 234 | else: 235 | r = self._call('getnewaddress') 236 | 237 | return CBitcoinAddress.from_str(r) 238 | 239 | def getaccountaddress(self, account=None): 240 | """Return the current Bitcoin address for receiving payments to this account.""" 241 | r = self._call('getaccountaddress', account) 242 | return CBitcoinAddress.from_str(r) 243 | 244 | def validateaddress(self, address): 245 | """Return information about an address""" 246 | r = self._call('validateaddress', str(address)) 247 | r['address'] = CBitcoinAddress.from_str(r['address']) 248 | return r 249 | -------------------------------------------------------------------------------- /bitcoin/messages.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # messages.py 4 | # 5 | # Distributed under the MIT/X11 software license, see the accompanying 6 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 7 | # 8 | 9 | from __future__ import absolute_import, division, print_function, unicode_literals 10 | 11 | import struct 12 | import time 13 | import random 14 | import cStringIO 15 | from bitcoin.coredefs import * 16 | from bitcoin.core import * 17 | 18 | MSG_TX = 1 19 | MSG_BLOCK = 2 20 | 21 | class msg_version(object): 22 | command = b"version" 23 | def __init__(self, protover=PROTO_VERSION): 24 | self.protover = MIN_PROTO_VERSION 25 | self.nVersion = protover 26 | self.nServices = 1 27 | self.nTime = time.time() 28 | self.addrTo = CAddress(MIN_PROTO_VERSION) 29 | self.addrFrom = CAddress(MIN_PROTO_VERSION) 30 | self.nNonce = random.getrandbits(64) 31 | self.strSubVer = b'/python-bitcoin-0.0.1/' 32 | self.nStartingHeight = -1 33 | def deserialize(self, f): 34 | self.nVersion = struct.unpack(b"= 106: 42 | self.addrFrom = CAddress(MIN_PROTO_VERSION) 43 | self.addrFrom.deserialize(f) 44 | self.nNonce = struct.unpack(b"= 209: 47 | self.nStartingHeight = struct.unpack(b" BIP0031_VERSION: 225 | self.nonce = struct.unpack(b" BIP0031_VERSION: 229 | r += struct.pack(b" self.pend: 429 | return None 430 | 431 | s = self.vch[self.pc:self.pc+n] 432 | self.pc += n 433 | 434 | return s 435 | 436 | def getop(self): 437 | s = self.getchars(1) 438 | if s is None: 439 | return False 440 | opcode = ord(s) 441 | 442 | sop = CScriptOp() 443 | sop.op = opcode 444 | sop.ser_len = 1 445 | 446 | if opcode > OP_PUSHDATA4: 447 | if opcode not in VALID_OPCODES: 448 | return False 449 | self.sop = sop 450 | return True 451 | 452 | if opcode < OP_PUSHDATA1: 453 | datasize = opcode 454 | 455 | elif opcode == OP_PUSHDATA1: 456 | sop.ser_len += 1 457 | s = self.getchars(1) 458 | if s is None: 459 | return False 460 | datasize = ord(s) 461 | 462 | elif opcode == OP_PUSHDATA2: 463 | sop.ser_len += 2 464 | s = self.getchars(2) 465 | if s is None: 466 | return False 467 | datasize = struct.unpack(b"= len(template): 505 | return None 506 | if not self.getop(): 507 | return None 508 | 509 | expected_op = template[i] 510 | if expected_op == OP_PUBKEYHASH or expected_op == OP_PUBKEY: 511 | if self.sop.op > OP_PUSHDATA4: 512 | return None 513 | l.append(self.sop.data) 514 | 515 | elif self.sop.op != expected_op: 516 | return None 517 | 518 | i += 1 519 | 520 | return l 521 | 522 | def match_alltemp(self, vch_in=None): 523 | for temp in TEMPLATES: 524 | l = self.match_temp(temp, vch_in) 525 | if l is not None: 526 | return l 527 | return None 528 | 529 | def __repr__(self): 530 | return "CScript(vchsz %d)" % (len(self.vch),) 531 | 532 | -------------------------------------------------------------------------------- /bitcoin/core.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # core.py 4 | # 5 | # Distributed under the MIT/X11 software license, see the accompanying 6 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 7 | # 8 | 9 | from __future__ import absolute_import, division, print_function, unicode_literals 10 | 11 | import struct 12 | import socket 13 | import binascii 14 | import time 15 | import hashlib 16 | from bitcoin.serialize import * 17 | from bitcoin.coredefs import * 18 | from bitcoin.script import CScript 19 | 20 | class CAddress(object): 21 | def __init__(self, protover=PROTO_VERSION): 22 | self.protover = protover 23 | self.nTime = 0 24 | self.nServices = 1 25 | self.pchReserved = b"\x00" * 10 + b"\xff" * 2 26 | self.ip = "0.0.0.0" 27 | self.port = 0 28 | def deserialize(self, f): 29 | if self.protover >= CADDR_TIME_VERSION: 30 | self.nTime = struct.unpack(b"H", f.read(2))[0] 35 | def serialize(self): 36 | r = b"" 37 | if self.protover >= CADDR_TIME_VERSION: 38 | r += struct.pack(b"H", self.port) 43 | return r 44 | def __repr__(self): 45 | return "CAddress(nTime=%d nServices=%i ip=%s port=%i)" % (self.nTime, self.nServices, self.ip, self.port) 46 | 47 | class CInv(object): 48 | typemap = { 49 | 0: "Error", 50 | 1: "TX", 51 | 2: "Block"} 52 | def __init__(self): 53 | self.type = 0 54 | self.hash = 0 55 | def deserialize(self, f): 56 | self.type = struct.unpack(b" 1: 269 | newhashes = [] 270 | for i in range(0, len(hashes), 2): 271 | i2 = min(i+1, len(hashes)-1) 272 | newhashes.append(hashlib.sha256(hashlib.sha256(hashes[i] + hashes[i2]).digest()).digest()) 273 | hashes = newhashes 274 | return uint256_from_str(hashes[0]) 275 | def is_valid(self): 276 | self.calc_sha256() 277 | target = uint256_from_compact(self.nBits) 278 | if self.sha256 > target: 279 | return False 280 | if self.calc_merkle() != self.hashMerkleRoot: 281 | return False 282 | return True 283 | def __repr__(self): 284 | return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx)) 285 | 286 | class CUnsignedAlert(object): 287 | def __init__(self): 288 | self.nVersion = 1 289 | self.nRelayUntil = 0 290 | self.nExpiration = 0 291 | self.nID = 0 292 | self.nCancel = 0 293 | self.setCancel = [] 294 | self.nMinVer = 0 295 | self.nMaxVer = 0 296 | self.setSubVer = [] 297 | self.nPriority = 0 298 | self.strComment = b"" 299 | self.strStatusBar = b"" 300 | self.strReserved = b"" 301 | def deserialize(self, f): 302 | self.nVersion = struct.unpack(b" '3': 13 | long = int 14 | 15 | import hashlib 16 | from bitcoin.serialize import Hash, Hash160, ser_uint256, ser_uint160 17 | from bitcoin.script import * 18 | from bitcoin.core import CTxOut, CTransaction 19 | from bitcoin.key import CKey 20 | from bitcoin.bignum import bn2vch, vch2bn 21 | 22 | def SignatureHash(script, txTo, inIdx, hashtype): 23 | if inIdx >= len(txTo.vin): 24 | return (1, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) 25 | txtmp = CTransaction() 26 | txtmp.copy(txTo) 27 | 28 | for txin in txtmp.vin: 29 | txin.scriptSig = b'' 30 | txtmp.vin[inIdx].scriptSig = script.vch 31 | 32 | if (hashtype & 0x1f) == SIGHASH_NONE: 33 | txtmp.vout = [] 34 | 35 | for i in range(len(txtmp.vin)): 36 | if i != inIdx: 37 | txtmp.vin[i].nSequence = 0 38 | 39 | elif (hashtype & 0x1f) == SIGHASH_SINGLE: 40 | outIdx = inIdx 41 | if outIdx >= len(txtmp.vout): 42 | return (1, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) 43 | 44 | tmp = txtmp.vout[outIdx] 45 | txtmp.vout = [] 46 | for i in range(outIdx): 47 | txtmp.vout.append(CTxOut()) 48 | txtmp.vout.append(tmp) 49 | 50 | for i in range(len(txtmp.vin)): 51 | if i != inIdx: 52 | txtmp.vin[i].nSequence = 0 53 | 54 | if hashtype & SIGHASH_ANYONECANPAY: 55 | tmp = txtmp.vin[inIdx] 56 | txtmp.vin = [] 57 | txtmp.vin.append(tmp) 58 | 59 | s = txtmp.serialize() 60 | s += struct.pack(b" 20: 88 | return False 89 | i += 1 90 | ikey = i 91 | i += keys_count 92 | if len(stack) < i: 93 | return False 94 | 95 | sigs_count = CastToBigNum(stack[-i]) 96 | if sigs_count < 0 or sigs_count > keys_count: 97 | return False 98 | i += 1 99 | isig = i 100 | i += sigs_count 101 | if len(stack) < i: 102 | return False 103 | 104 | for k in range(sigs_count): 105 | sig = stack[-isig-k] 106 | # FIXME: find-and-delete sig in script 107 | 108 | success = True 109 | 110 | while success and sigs_count > 0: 111 | sig = stack[-isig] 112 | pubkey = stack[-ikey] 113 | 114 | if CheckSig(sig, pubkey, script, txTo, inIdx, hashtype): 115 | isig += 1 116 | sigs_count -= 1 117 | 118 | ikey += 1 119 | keys_count -= 1 120 | 121 | if sigs_count > keys_count: 122 | success = False 123 | 124 | while i > 0: 125 | stack.pop() 126 | i -= 1 127 | 128 | if success: 129 | stack.append(b"\x01") 130 | else: 131 | stack.append(b"\x00") 132 | 133 | if opcode == OP_CHECKMULTISIGVERIFY: 134 | if success: 135 | stack.pop() 136 | else: 137 | return False 138 | 139 | return True 140 | 141 | def dumpstack(msg, stack): 142 | print("%s stacksz %d" % (msg, len(stack))) 143 | for i in range(len(stack)): 144 | vch = stack[i] 145 | print("#%d: %s" % (i, vch.encode('hex'))) 146 | 147 | ISA_UNOP = { 148 | OP_1ADD, 149 | OP_1SUB, 150 | OP_2MUL, 151 | OP_2DIV, 152 | OP_NEGATE, 153 | OP_ABS, 154 | OP_NOT, 155 | OP_0NOTEQUAL, 156 | } 157 | 158 | def UnaryOp(opcode, stack): 159 | if len(stack) < 1: 160 | return False 161 | bn = CastToBigNum(stack.pop()) 162 | 163 | if opcode == OP_1ADD: 164 | bn += 1 165 | 166 | elif opcode == OP_1SUB: 167 | bn -= 1 168 | 169 | elif opcode == OP_2MUL: 170 | bn <<= 1 171 | 172 | elif opcode == OP_2DIV: 173 | bn >>= 1 174 | 175 | elif opcode == OP_NEGATE: 176 | bn = -bn 177 | 178 | elif opcode == OP_ABS: 179 | if bn < 0: 180 | bn = -bn 181 | 182 | elif opcode == OP_NOT: 183 | bn = long(bn == 0) 184 | 185 | elif opcode == OP_0NOTEQUAL: 186 | bn = long(bn != 0) 187 | 188 | else: 189 | return False 190 | 191 | stack.append(bn2vch(bn)) 192 | 193 | return True 194 | 195 | ISA_BINOP = { 196 | OP_ADD, 197 | OP_SUB, 198 | OP_LSHIFT, 199 | OP_RSHIFT, 200 | OP_BOOLAND, 201 | OP_BOOLOR, 202 | OP_NUMEQUAL, 203 | OP_NUMEQUALVERIFY, 204 | OP_NUMNOTEQUAL, 205 | OP_LESSTHAN, 206 | OP_GREATERTHAN, 207 | OP_LESSTHANOREQUAL, 208 | OP_GREATERTHANOREQUAL, 209 | OP_MIN, 210 | OP_MAX, 211 | } 212 | 213 | def BinOp(opcode, stack): 214 | if len(stack) < 2: 215 | return False 216 | 217 | bn2 = CastToBigNum(stack.pop()) 218 | bn1 = CastToBigNum(stack.pop()) 219 | 220 | if opcode == OP_ADD: 221 | bn = bn1 + bn2 222 | 223 | elif opcode == OP_SUB: 224 | bn = bn1 - bn2 225 | 226 | elif opcode == OP_LSHIFT: 227 | if bn2 < 0 or bn2 > 2048: 228 | return False 229 | bn = bn1 << bn2 230 | 231 | elif opcode == OP_RSHIFT: 232 | if bn2 < 0 or bn2 > 2048: 233 | return False 234 | bn = bn1 >> bn2 235 | 236 | elif opcode == OP_BOOLAND: 237 | bn = long(bn1 != 0 and bn2 != 0) 238 | 239 | elif opcode == OP_BOOLOR: 240 | bn = long(bn1 != 0 or bn2 != 0) 241 | 242 | elif opcode == OP_NUMEQUAL or opcode == OP_NUMEQUALVERIFY: 243 | bn = long(bn1 == bn2) 244 | 245 | elif opcode == OP_NUMNOTEQUAL: 246 | bn = long(bn1 != bn2) 247 | 248 | elif opcode == OP_LESSTHAN: 249 | bn = long(bn1 < bn2) 250 | 251 | elif opcode == OP_GREATERTHAN: 252 | bn = long(bn1 > bn2) 253 | 254 | elif opcode == OP_LESSTHANOREQUAL: 255 | bn = long(bn1 <= bn2) 256 | 257 | elif opcode == OP_GREATERTHANOREQUAL: 258 | bn = long(bn1 >= bn2) 259 | 260 | elif opcode == OP_MIN: 261 | if bn1 < bn2: 262 | bn = bn1 263 | else: 264 | bn = bn2 265 | 266 | elif opcode == OP_MAX: 267 | if bn1 > bn2: 268 | bn = bn1 269 | else: 270 | bn = bn2 271 | 272 | else: 273 | return False # unknown binop opcode 274 | 275 | stack.append(bn2vch(bn)) 276 | 277 | if opcode == OP_NUMEQUALVERIFY: 278 | if CastToBool(stack[-1]): 279 | stack.pop() 280 | else: 281 | return False 282 | 283 | return True 284 | 285 | def CheckExec(vfExec): 286 | for b in vfExec: 287 | if not b: 288 | return False 289 | return True 290 | 291 | def EvalScript(stack, scriptIn, txTo, inIdx, hashtype): 292 | altstack = [] 293 | vfExec = [] 294 | script = CScript(scriptIn) 295 | while script.pc < script.pend: 296 | if not script.getop(): 297 | return False 298 | sop = script.sop 299 | 300 | fExec = CheckExec(vfExec) 301 | 302 | if fExec and sop.op <= OP_PUSHDATA4: 303 | stack.append(sop.data) 304 | continue 305 | 306 | elif fExec and sop.op == OP_1NEGATE or ((sop.op >= OP_1) and (sop.op <= OP_16)): 307 | v = sop.op - (OP_1 - 1) 308 | stack.append(bn2vch(v)) 309 | 310 | elif fExec and sop.op in ISA_BINOP: 311 | if not BinOp(sop.op, stack): 312 | return False 313 | 314 | elif fExec and sop.op in ISA_UNOP: 315 | if not UnaryOp(sop.op, stack): 316 | return False 317 | 318 | elif fExec and sop.op == OP_2DROP: 319 | if len(stack) < 2: 320 | return False 321 | stack.pop() 322 | stack.pop() 323 | 324 | elif fExec and sop.op == OP_2DUP: 325 | if len(stack) < 2: 326 | return False 327 | v1 = stack[-2] 328 | v2 = stack[-1] 329 | stack.append(v1) 330 | stack.append(v2) 331 | 332 | elif fExec and sop.op == OP_2OVER: 333 | if len(stack) < 4: 334 | return False 335 | v1 = stack[-4] 336 | v2 = stack[-3] 337 | stack.append(v1) 338 | stack.append(v2) 339 | 340 | elif fExec and sop.op == OP_2SWAP: 341 | if len(stack) < 4: 342 | return False 343 | tmp = stack[-4] 344 | stack[-4] = stack[-2] 345 | stack[-2] = tmp 346 | 347 | tmp = stack[-3] 348 | stack[-3] = stack[-1] 349 | stack[-1] = tmp 350 | 351 | elif fExec and sop.op == OP_3DUP: 352 | if len(stack) < 3: 353 | return False 354 | v1 = stack[-3] 355 | v2 = stack[-2] 356 | v3 = stack[-1] 357 | stack.append(v1) 358 | stack.append(v2) 359 | stack.append(v3) 360 | 361 | elif fExec and sop.op == OP_CHECKMULTISIG or sop.op == OP_CHECKMULTISIGVERIFY: 362 | tmpScript = CScript(script.vch[script.pbegincodehash:script.pend]) 363 | ok = CheckMultiSig(sop.op, tmpScript, stack, txTo, 364 | inIdx, hashtype) 365 | if not ok: 366 | return False 367 | 368 | elif fExec and sop.op == OP_CHECKSIG or sop.op == OP_CHECKSIGVERIFY: 369 | if len(stack) < 2: 370 | return False 371 | vchPubKey = stack.pop() 372 | vchSig = stack.pop() 373 | tmpScript = CScript(script.vch[script.pbegincodehash:script.pend]) 374 | 375 | # FIXME: find-and-delete vchSig 376 | 377 | ok = CheckSig(vchSig, vchPubKey, tmpScript, 378 | txTo, inIdx, hashtype) 379 | if ok: 380 | if sop.op != OP_CHECKSIGVERIFY: 381 | stack.append(b"\x01") 382 | else: 383 | if sop.op == OP_CHECKSIGVERIFY: 384 | return False 385 | stack.append(b"\x00") 386 | 387 | elif fExec and sop.op == OP_CODESEPARATOR: 388 | script.pbegincodehash = script.pc 389 | 390 | elif fExec and sop.op == OP_DEPTH: 391 | bn = len(stack) 392 | stack.append(bn2vch(bn)) 393 | 394 | elif fExec and sop.op == OP_DROP: 395 | if len(stack) < 1: 396 | return False 397 | stack.pop() 398 | 399 | elif fExec and sop.op == OP_DUP: 400 | if len(stack) < 1: 401 | return False 402 | v = stack[-1] 403 | stack.append(v) 404 | 405 | elif sop.op == OP_ELSE: 406 | if len(vfExec) == 0: 407 | return false 408 | vfExec[-1] = not vfExec[-1] 409 | 410 | elif sop.op == OP_ENDIF: 411 | if len(vfExec) == 0: 412 | return false 413 | vfExec.pop() 414 | 415 | elif fExec and sop.op == OP_EQUAL or sop.op == OP_EQUALVERIFY: 416 | if len(stack) < 2: 417 | return False 418 | v1 = stack.pop() 419 | v2 = stack.pop() 420 | 421 | is_equal = (v1 == v2) 422 | if is_equal: 423 | stack.append(b"\x01") 424 | else: 425 | stack.append(b"\x00") 426 | 427 | if sop.op == OP_EQUALVERIFY: 428 | if is_equal: 429 | stack.pop() 430 | else: 431 | return False 432 | 433 | elif fExec and sop.op == OP_FROMALTSTACK: 434 | if len(altstack) < 1: 435 | return False 436 | v = altstack.pop() 437 | stack.append(v) 438 | 439 | elif fExec and sop.op == OP_HASH160: 440 | if len(stack) < 1: 441 | return False 442 | stack.append(ser_uint160(Hash160(stack.pop()))) 443 | 444 | elif fExec and sop.op == OP_HASH256: 445 | if len(stack) < 1: 446 | return False 447 | stack.append(ser_uint256(Hash(stack.pop()))) 448 | 449 | elif sop.op == OP_IF or sop.op == OP_NOTIF: 450 | val = False 451 | 452 | if fExec: 453 | if len(stack) < 1: 454 | return False 455 | vch = stack.pop() 456 | val = CastToBool(vch) 457 | if sop.op == OP_NOTIF: 458 | val = not val 459 | 460 | vfExec.append(val) 461 | 462 | elif fExec and sop.op == OP_IFDUP: 463 | if len(stack) < 1: 464 | return False 465 | vch = stack[-1] 466 | if CastToBool(vch): 467 | stack.append(vch) 468 | 469 | elif fExec and sop.op == OP_NIP: 470 | if len(stack) < 2: 471 | return False 472 | del stack[-2] 473 | 474 | elif fExec and sop.op == OP_NOP or (sop.op >= OP_NOP1 and sop.op <= OP_NOP10): 475 | pass 476 | 477 | elif fExec and sop.op == OP_OVER: 478 | if len(stack) < 2: 479 | return False 480 | vch = stack[-2] 481 | stack.append(vch) 482 | 483 | elif fExec and sop.op == OP_PICK or sop.op == OP_ROLL: 484 | if len(stack) < 2: 485 | return False 486 | n = CastToBigNum(stack.pop()) 487 | if n < 0 or n >= len(stack): 488 | return False 489 | vch = stack[-n-1] 490 | if sop.op == OP_ROLL: 491 | del stack[-n-1] 492 | stack.append(vch) 493 | 494 | elif fExec and sop.op == OP_RETURN: 495 | return False 496 | 497 | elif fExec and sop.op == OP_RIPEMD160: 498 | if len(stack) < 1: 499 | return False 500 | 501 | h = hashlib.new('ripemd160') 502 | h.update(stack.pop()) 503 | stack.append(h.digest()) 504 | 505 | elif fExec and sop.op == OP_ROT: 506 | if len(stack) < 3: 507 | return False 508 | tmp = stack[-3] 509 | stack[-3] = stack[-2] 510 | stack[-2] = tmp 511 | 512 | tmp = stack[-2] 513 | stack[-2] = stack[-1] 514 | stack[-1] = tmp 515 | 516 | elif fExec and sop.op == OP_SIZE: 517 | if len(stack) < 1: 518 | return False 519 | bn = len(stack[-1]) 520 | stack.append(bn2vch(bn)) 521 | 522 | elif fExec and sop.op == OP_SHA256: 523 | if len(stack) < 1: 524 | return False 525 | stack.append(hashlib.sha256(stack.pop()).digest()) 526 | 527 | elif fExec and sop.op == OP_SWAP: 528 | if len(stack) < 2: 529 | return False 530 | tmp = stack[-2] 531 | stack[-2] = stack[-1] 532 | stack[-1] = tmp 533 | 534 | elif fExec and sop.op == OP_TOALTSTACK: 535 | if len(stack) < 1: 536 | return False 537 | v = stack.pop() 538 | altstack.append(v) 539 | 540 | elif fExec and sop.op == OP_TUCK: 541 | if len(stack) < 2: 542 | return False 543 | vch = stack[-1] 544 | stack.insert(len(stack) - 2, vch) 545 | 546 | elif fExec and sop.op == OP_VERIFY: 547 | if len(stack) < 1: 548 | return False 549 | v = CastToBool(stack[-1]) 550 | if v: 551 | stack.pop() 552 | else: 553 | return False 554 | 555 | elif fExec and sop.op == OP_WITHIN: 556 | if len(stack) < 3: 557 | return False 558 | bn3 = CastToBigNum(stack.pop()) 559 | bn2 = CastToBigNum(stack.pop()) 560 | bn1 = CastToBigNum(stack.pop()) 561 | v = (bn2 <= bn1) and (bn1 < bn3) 562 | if v: 563 | stack.append(b"\x01") 564 | else: 565 | stack.append(b"\x00") 566 | 567 | elif fExec: 568 | #print("Unsupported opcode", OPCODE_NAMES[sop.op]) 569 | return False 570 | 571 | return True 572 | 573 | def CastToBigNum(s): 574 | v = vch2bn(s) 575 | return v 576 | 577 | def CastToBool(s): 578 | for i in range(len(s)): 579 | sv = ord(s[i]) 580 | if sv != 0: 581 | if (i == (len(s) - 1)) and (sv == 0x80): 582 | return False 583 | return True 584 | 585 | return False 586 | 587 | def VerifyScript(scriptSig, scriptPubKey, txTo, inIdx, hashtype): 588 | stack = [] 589 | if not EvalScript(stack, scriptSig, txTo, inIdx, hashtype): 590 | return False 591 | if not EvalScript(stack, scriptPubKey, txTo, inIdx, hashtype): 592 | return False 593 | if len(stack) == 0: 594 | return False 595 | return CastToBool(stack[-1]) 596 | 597 | def VerifySignature(txFrom, txTo, inIdx, hashtype): 598 | if inIdx >= len(txTo.vin): 599 | return False 600 | txin = txTo.vin[inIdx] 601 | 602 | if txin.prevout.n >= len(txFrom.vout): 603 | return False 604 | txout = txFrom.vout[txin.prevout.n] 605 | 606 | txFrom.calc_sha256() 607 | 608 | if txin.prevout.hash != txFrom.sha256: 609 | return False 610 | 611 | if not VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, inIdx, 612 | hashtype): 613 | return False 614 | 615 | return True 616 | 617 | 618 | 619 | 620 | --------------------------------------------------------------------------------