Skip to content

Commit 28518d2

Browse files
committed
Implement testnet/mainnet/regtest chain selection
1 parent 85ffad9 commit 28518d2

7 files changed

Lines changed: 141 additions & 89 deletions

File tree

README

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ python-bitcoinlib
22
-----------------
33

44
This Python2/3 library provides an easy interface to the bitcoin data
5-
structures and protocol.
5+
structures and protocol. The approach is low-level and "ground up", with a
6+
focus on providing tools to manipulate the internals of how Bitcoin works.
67

78

89
Structure
910
---------
1011

11-
Everything consensus critical is found in the modules under bitcoin.core:
12+
Everything consensus critical is found in the modules under bitcoin.core. This
13+
rule is followed pretty strictly, for instance chain parameters are split into
14+
consensus critical and non-consensus-critical.
1215

1316
bitcoin.core - Basic datastructures, CTransaction, CBlock etc.
1417
bitcoin.core.bignum - Bignum handling
@@ -21,6 +24,7 @@ bitcoin.core.serialize - Serialization
2124
In the future the bitcoin.core may use the Satoshi sourcecode directly as a
2225
libary. Non-consensus critical modules include the following:
2326

27+
bitcoin - Chain selection
2428
bitcoin.base58 - Base58 encoding
2529
bitcoin.bloom - Bloom filters (incomplete)
2630
bitcoin.net - Network communication (broken currently)
@@ -40,6 +44,19 @@ Example Code
4044
See examples/ directory.
4145

4246

47+
Selecting the chain to use
48+
--------------------------
49+
50+
Do the following:
51+
52+
import bitcoin
53+
bitcoin.SelectChain(NAME)
54+
55+
Where NAME is one of 'testnet', 'mainnet', or 'regtest'. The chain currently
56+
selected is a global variable that changes behavior everywhere, just like in
57+
the Satoshi codebase.
58+
59+
4360
Unit tests
4461
----------
4562

bitcoin/__init__.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,58 @@
22
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
33

44
from __future__ import absolute_import, division, print_function, unicode_literals
5+
6+
import bitcoin.core
7+
8+
class MainParams(bitcoin.core.CoreChainParams):
9+
MESSAGE_START = b'\xf9\xbe\xb4\xd9'
10+
DEFAULT_PORT = 8333
11+
RPC_PORT = 8332
12+
DNS_SEEDS = (('bitcoin.sipa.be', 'seed.bitcoin.sipa.be'),
13+
('bluematt.me', 'dnsseed.bluematt.me'),
14+
('dashjr.org', 'dnsseed.bitcoin.dashjr.org'),
15+
('bitcoinstats.com', 'seed.bitcoinstats.com'),
16+
('xf2.org', 'bitseed.xf2.org'))
17+
BASE58_PREFIXES = {'PUBKEY_ADDR':0,
18+
'SCRIPT_ADDR':5,
19+
'SECRET_KEY' :128}
20+
21+
class TestNetParams(bitcoin.core.CoreTestNetParams):
22+
MESSAGE_START = b'\x0b\x11\x09\x07'
23+
DEFAULT_PORT = 18333
24+
RPC_PORT = 18332
25+
DNS_SEEDS = (('bitcoin.petertodd.org', 'testnet-seed.bitcoin.petertodd.org'),
26+
('bluematt.me', 'testnet-seed.bluematt.me'))
27+
BASE58_PREFIXES = {'PUBKEY_ADDR':111,
28+
'SCRIPT_ADDR':196,
29+
'SECRET_KEY' :239}
30+
31+
class RegTestParams(bitcoin.core.CoreRegTestParams):
32+
MESSAGE_START = b'\xfa\xbf\xb5\xda'
33+
DEFAULT_PORT = 18444
34+
RPC_PORT = 18332
35+
DNS_SEEDS = ()
36+
BASE58_PREFIXES = {'PUBKEY_ADDR':111,
37+
'SCRIPT_ADDR':196,
38+
'SECRET_KEY' :239}
39+
40+
"""Master global setting for what chain params we're using.
41+
42+
However, don't set this directly, use SelectParams() instead so as to set the
43+
bitcoin.core.params correctly too.
44+
"""
45+
#params = bitcoin.core.coreparams = MainParams()
46+
params = MainParams()
47+
48+
def SelectParams(name):
49+
"""Select the chain parameters to use"""
50+
global params
51+
bitcoin.core._SelectCoreParams(name)
52+
if name == 'mainnet':
53+
params = bitcoin.core.coreparams = MainParams()
54+
elif name == 'testnet':
55+
params = bitcoin.core.coreparams = TestNetParams()
56+
elif name == 'regtest':
57+
params = bitcoin.core.coreparams = RegTestParams()
58+
else:
59+
raise ValueError('Unknown chain %r' % name)

bitcoin/core/__init__.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@
1616
from .script import CScript
1717

1818
from .serialize import *
19-
from .coredefs import *
19+
20+
# Core definitions
21+
COIN = 100000000
22+
MAX_MONEY = 21000000 * COIN
23+
MAX_BLOCK_SIZE = 1000000
24+
MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50
25+
26+
def MoneyRange(nValue):
27+
return 0<= nValue <= MAX_MONEY
2028

2129
def x(h):
2230
"""Convert a hex string to bytes"""
@@ -313,6 +321,49 @@ def calc_merkle_root(self):
313321
return CBlock.calc_merkle_root_from_hashes(hashes)
314322

315323

324+
class CoreChainParams(object):
325+
"""Define consensus-critical parameters of a given instance of the Bitcoin system"""
326+
GENESIS_BLOCK = None
327+
PROOF_OF_WORK_LIMIT = None
328+
SUBSIDY_HALVING_INTERVAL = None
329+
NAME = None
330+
331+
class CoreMainParams(CoreChainParams):
332+
NAME = 'mainnet'
333+
GENESIS_BLOCK = CBlock.deserialize(x('0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'))
334+
SUBSIDY_HALVING_INTERVAL = 210000
335+
PROOF_OF_WORK_LIMIT = 2**256-1 >> 32
336+
337+
class CoreTestNetParams(CoreMainParams):
338+
NAME = 'testnet'
339+
GENESIS_BLOCK = CBlock.deserialize(x('0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'))
340+
341+
class CoreRegTestParams(CoreTestNetParams):
342+
NAME = 'regtest'
343+
GENESIS_BLOCK = CBlock.deserialize(x('0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'))
344+
SUBSIDY_HALVING_INTERVAL = 150
345+
PROOF_OF_WORK_LIMIT = 2**256-1 >> 1
346+
347+
"""Master global setting for what core chain params we're using"""
348+
coreparams = CoreMainParams()
349+
350+
def _SelectCoreParams(name):
351+
"""Select the core chain parameters to use
352+
353+
Don't use this directly, use bitcoin.SelectParams() instead so both
354+
consensus-critical and general parameters are set properly.
355+
"""
356+
global coreparams
357+
if name == 'mainnet':
358+
coreparams = CoreMainParams()
359+
elif name == 'testnet':
360+
coreparams = CoreTestNetParams()
361+
elif name == 'regtest':
362+
coreparams = CoreRegTestParams()
363+
else:
364+
raise ValueError('Unknown chain %r' % name)
365+
366+
316367
class CheckTransactionError(ValidationError):
317368
pass
318369

@@ -376,7 +427,7 @@ def CheckProofOfWork(hash, nBits):
376427
target = uint256_from_compact(nBits)
377428

378429
# Check range
379-
if not (0 < target <= PROOF_OF_WORK_LIMIT):
430+
if not (0 < target <= coreparams.PROOF_OF_WORK_LIMIT):
380431
raise CheckProofOfWorkError("CheckProofOfWork() : nBits below minimum work")
381432

382433
# Check proof of work matches claimed amount

bitcoin/core/coredefs.py

Lines changed: 0 additions & 67 deletions
This file was deleted.

bitcoin/rpc.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@
5151
except ImportError:
5252
import urlparse
5353

54-
from bitcoin.core import lx, b2lx, CBlock, CTransaction, COutPoint, CTxOut
54+
import bitcoin
55+
from bitcoin.core import COIN, lx, b2lx, CBlock, CTransaction, COutPoint, CTxOut
5556
from bitcoin.core.script import CScript
56-
from bitcoin.core.coredefs import COIN
5757
from bitcoin.wallet import CBitcoinAddress
5858

5959
USER_AGENT = "AuthServiceProxy/0.1"
@@ -78,7 +78,7 @@ def __init__(self, rpc_error):
7878
class RawProxy(object):
7979
# FIXME: need a CChainParams rather than hard-coded service_port
8080
def __init__(self, service_url=None,
81-
service_port=8332,
81+
service_port=None,
8282
btc_conf_file=None,
8383
timeout=HTTP_TIMEOUT,
8484
_connection=None):
@@ -109,6 +109,8 @@ def __init__(self, service_url=None,
109109
k, v = line.split('=', 1)
110110
conf[k.strip()] = v.strip()
111111

112+
if service_port is None:
113+
service_port = bitcoin.params.RPC_PORT
112114
conf['rpcport'] = int(conf.get('rpcport', service_port))
113115
conf['rpcssl'] = conf.get('rpcssl', '0')
114116

@@ -206,7 +208,7 @@ def _get_response(self):
206208

207209
class Proxy(RawProxy):
208210
def __init__(self, service_url=None,
209-
service_port=8332,
211+
service_port=None,
210212
btc_conf_file=None,
211213
timeout=HTTP_TIMEOUT,
212214
**kwargs):

bitcoin/wallet.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,19 @@
1414

1515
from __future__ import absolute_import, division, print_function, unicode_literals
1616

17+
import bitcoin
1718
import bitcoin.base58
1819
import bitcoin.core.script as script
1920

2021
class CBitcoinAddress(bitcoin.base58.CBase58Data):
2122
"""A Bitcoin address"""
22-
PUBKEY_ADDRESS = 0
23-
SCRIPT_ADDRESS = 5
24-
PUBKEY_ADDRESS_TEST = 111
25-
SCRIPT_ADDRESS_TEST = 196
2623

2724
def to_scriptPubKey(self):
2825
"""Convert an address to a scriptPubKey"""
29-
if self.nVersion in (self.PUBKEY_ADDRESS, self.PUBKEY_ADDRESS_TEST):
26+
if self.nVersion == bitcoin.params.BASE58_PREFIXES['PUBKEY_ADDR']:
3027
return script.CScript([script.OP_DUP, script.OP_HASH160, self, script.OP_EQUALVERIFY, script.OP_CHECKSIG])
3128

32-
elif self.nVersion in (self.SCRIPT_ADDRESS, self.SCRIPT_ADDRESS_TEST):
29+
elif self.nVersion == bitcoin.params.BASE58_PREFIXES['SCRIPT_ADDR']:
3330
return script.CScript([script.OP_HASH160, self, script.OP_EQUAL])
3431

3532
else:

examples/make-bootstrap-rpc.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,24 @@
88

99
"""Make a boostrap.dat file by getting the blocks from the RPC interface."""
1010

11+
import bitcoin
1112
from bitcoin.core import CBlock
12-
import bitcoin.core.coredefs
1313
import bitcoin.rpc
1414

1515
import struct
1616
import sys
1717
import time
1818

19-
msg_start = bitcoin.core.coredefs.NETWORKS['mainnet'].msg_start
2019
try:
2120
if len(sys.argv) not in (2, 3):
2221
raise Exception
2322

2423
n = int(sys.argv[1])
2524

26-
if len(sys.argv) == 2:
27-
msg_start = bitcoin.core.coredefs.NETWORKS[sys.argv[2]].msg_start
25+
if len(sys.argv) == 3:
26+
bitcoin.SelectParams(sys.argv[2])
2827
except Exception as ex:
29-
print('Usage: %s <block-height> [network=mainnet] > bootstrap.dat' % sys.argv[0], file=sys.stderr)
30-
print('', file=sys.stderr)
31-
print('Where network is one of %s' % (tuple(bitcoin.core.coredefs.NETWORKS.keys()),), file=sys.stderr)
28+
print('Usage: %s <block-height> [network=(mainnet|testnet|regtest)] > bootstrap.dat' % sys.argv[0], file=sys.stderr)
3229
sys.exit(1)
3330

3431

@@ -49,6 +46,6 @@
4946
i, len(block_bytes)),
5047
file=sys.stderr)
5148

52-
fd.write(msg_start)
49+
fd.write(bitcoin.params.MESSAGE_START)
5350
fd.write(struct.pack('<i', len(block_bytes)))
5451
fd.write(block_bytes)

0 commit comments

Comments
 (0)