Skip to content

Commit 7252669

Browse files
committed
Implement segwit
1 parent e97db32 commit 7252669

File tree

9 files changed

+234
-103
lines changed

9 files changed

+234
-103
lines changed

p2pool/bitcoin/data.py

+93-15
Original file line numberDiff line numberDiff line change
@@ -91,30 +91,87 @@ def write(self, file, item):
9191
('port', pack.IntType(16, 'big')),
9292
])
9393

94-
tx_type = pack.ComposedType([
95-
('version', pack.IntType(32)),
96-
('tx_ins', pack.ListType(pack.ComposedType([
97-
('previous_output', pack.PossiblyNoneType(dict(hash=0, index=2**32 - 1), pack.ComposedType([
98-
('hash', pack.IntType(256)),
99-
('index', pack.IntType(32)),
100-
]))),
101-
('script', pack.VarStrType()),
102-
('sequence', pack.PossiblyNoneType(2**32 - 1, pack.IntType(32))),
103-
]))),
104-
('tx_outs', pack.ListType(pack.ComposedType([
105-
('value', pack.IntType(64)),
106-
('script', pack.VarStrType()),
94+
def is_segwit_tx(tx):
95+
return tx.get('marker', -1) == 0 and tx.get('flag', -1) >= 1
96+
97+
tx_in_type = pack.ComposedType([
98+
('previous_output', pack.PossiblyNoneType(dict(hash=0, index=2**32 - 1), pack.ComposedType([
99+
('hash', pack.IntType(256)),
100+
('index', pack.IntType(32)),
107101
]))),
108-
('lock_time', pack.IntType(32)),
102+
('script', pack.VarStrType()),
103+
('sequence', pack.PossiblyNoneType(2**32 - 1, pack.IntType(32))),
109104
])
110105

106+
tx_out_type = pack.ComposedType([
107+
('value', pack.IntType(64)),
108+
('script', pack.VarStrType()),
109+
])
110+
111+
tx_id_type = pack.ComposedType([
112+
('version', pack.IntType(32)),
113+
('tx_ins', pack.ListType(tx_in_type)),
114+
('tx_outs', pack.ListType(tx_out_type)),
115+
('lock_time', pack.IntType(32))
116+
])
117+
118+
class TransactionType(pack.Type):
119+
_int_type = pack.IntType(32)
120+
_varint_type = pack.VarIntType()
121+
_witness_type = pack.ListType(pack.VarStrType())
122+
_wtx_type = pack.ComposedType([
123+
('flag', pack.IntType(8)),
124+
('tx_ins', pack.ListType(tx_in_type)),
125+
('tx_outs', pack.ListType(tx_out_type))
126+
])
127+
_ntx_type = pack.ComposedType([
128+
('tx_outs', pack.ListType(tx_out_type)),
129+
('lock_time', _int_type)
130+
])
131+
_write_type = pack.ComposedType([
132+
('version', _int_type),
133+
('marker', pack.IntType(8)),
134+
('flag', pack.IntType(8)),
135+
('tx_ins', pack.ListType(tx_in_type)),
136+
('tx_outs', pack.ListType(tx_out_type))
137+
])
138+
139+
def read(self, file):
140+
version, file = self._int_type.read(file)
141+
marker, file = self._varint_type.read(file)
142+
if marker == 0:
143+
next, file = self._wtx_type.read(file)
144+
witness = [None]*len(next['tx_ins'])
145+
for i in xrange(len(next['tx_ins'])):
146+
witness[i], file = self._witness_type.read(file)
147+
locktime, file = self._int_type.read(file)
148+
return dict(version=version, marker=marker, flag=next['flag'], tx_ins=next['tx_ins'], tx_outs=next['tx_outs'], witness=witness, lock_time=locktime), file
149+
else:
150+
tx_ins = [None]*marker
151+
for i in xrange(marker):
152+
tx_ins[i], file = tx_in_type.read(file)
153+
next, file = self._ntx_type.read(file)
154+
return dict(version=version, tx_ins=tx_ins, tx_outs=next['tx_outs'], lock_time=next['lock_time']), file
155+
156+
def write(self, file, item):
157+
if is_segwit_tx(item):
158+
assert len(item['tx_ins']) == len(item['witness'])
159+
res = self._write_type.pack(item)
160+
for w in item['witness']:
161+
res += self._witness_type.pack(w)
162+
res += self._int_type.pack(item['lock_time'])
163+
return file, res
164+
return tx_id_type.write(file, item)
165+
166+
tx_type = TransactionType()
167+
111168
merkle_link_type = pack.ComposedType([
112169
('branch', pack.ListType(pack.IntType(256))),
113170
('index', pack.IntType(32)),
114171
])
115172

116173
merkle_tx_type = pack.ComposedType([
117-
('tx', tx_type),
174+
('tx', tx_id_type), # used only in aux_pow_type
118175
('block_hash', pack.IntType(256)),
119176
('merkle_link', merkle_link_type),
120177
])
@@ -133,6 +190,11 @@ def write(self, file, item):
133190
('txs', pack.ListType(tx_type)),
134191
])
135192

193+
stripped_block_type = pack.ComposedType([
194+
('header', block_header_type),
195+
('txs', pack.ListType(tx_id_type)),
196+
])
197+
136198
# merged mining
137199

138200
aux_pow_type = pack.ComposedType([
@@ -264,6 +326,22 @@ def address_to_pubkey_hash(address, net):
264326

265327
# transactions
266328

329+
def get_witness_commitment_hash(witness_root_hash, witness_reserved_value):
330+
return hash256(merkle_record_type.pack(dict(left=witness_root_hash, right=witness_reserved_value)))
331+
332+
def get_wtxid(tx, txid=None, txhash=None):
333+
has_witness = False
334+
if is_segwit_tx(tx):
335+
assert len(tx['tx_ins']) == len(tx['witness'])
336+
has_witness = any(len(w) > 0 for w in tx['witness'])
337+
if has_witness:
338+
return hash256(tx_type.pack(tx)) if txhash is None else txhash
339+
else:
340+
return hash256(tx_id_type.pack(tx)) if txid is None else txid
341+
342+
def get_txid(tx):
343+
return hash256(tx_id_type.pack(tx))
344+
267345
def pubkey_to_script2(pubkey):
268346
assert len(pubkey) <= 75
269347
return (chr(len(pubkey)) + pubkey) + '\xac'

p2pool/bitcoin/helper.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def check(bitcoind, net):
3939
def getwork(bitcoind, use_getblocktemplate=False):
4040
def go():
4141
if use_getblocktemplate:
42-
return bitcoind.rpc_getblocktemplate(dict(mode='template'))
42+
return bitcoind.rpc_getblocktemplate(dict(mode='template', rules=['segwit']))
4343
else:
4444
return bitcoind.rpc_getmemorypool()
4545
try:
@@ -71,6 +71,7 @@ def go():
7171
bits=bitcoin_data.FloatingIntegerType().unpack(work['bits'].decode('hex')[::-1]) if isinstance(work['bits'], (str, unicode)) else bitcoin_data.FloatingInteger(work['bits']),
7272
coinbaseflags=work['coinbaseflags'].decode('hex') if 'coinbaseflags' in work else ''.join(x.decode('hex') for x in work['coinbaseaux'].itervalues()) if 'coinbaseaux' in work else '',
7373
height=work['height'],
74+
rules=work.get('rules', []),
7475
last_update=time.time(),
7576
use_getblocktemplate=use_getblocktemplate,
7677
latency=end - start,
@@ -86,9 +87,11 @@ def submit_block_p2p(block, factory, net):
8687
@deferral.retry('Error submitting block: (will retry)', 10, 10)
8788
@defer.inlineCallbacks
8889
def submit_block_rpc(block, ignore_failure, bitcoind, bitcoind_work, net):
90+
segwit_rules = set(['!segwit', 'segwit'])
91+
segwit_activated = len(segwit_rules - set(bitcoind_work.value['rules'])) < len(segwit_rules)
8992
if bitcoind_work.value['use_getblocktemplate']:
9093
try:
91-
result = yield bitcoind.rpc_submitblock(bitcoin_data.block_type.pack(block).encode('hex'))
94+
result = yield bitcoind.rpc_submitblock((bitcoin_data.block_type if segwit_activated else bitcoin_data.stripped_block_type).pack(block).encode('hex'))
9295
except jsonrpc.Error_for_code(-32601): # Method not found, for older litecoin versions
9396
result = yield bitcoind.rpc_getblocktemplate(dict(mode='submit', data=bitcoin_data.block_type.pack(block).encode('hex')))
9497
success = result is None

p2pool/bitcoin/stratum.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def rpc_submit(self, worker_name, job_id, extranonce2, ntime, nonce):
6666
header = dict(
6767
version=x['version'],
6868
previous_block=x['previous_block'],
69-
merkle_root=bitcoin_data.check_merkle_link(bitcoin_data.hash256(new_packed_gentx), x['merkle_link']),
69+
merkle_root=bitcoin_data.check_merkle_link(bitcoin_data.hash256(new_packed_gentx), x['merkle_link']), # new_packed_gentx has witness data stripped
7070
timestamp=pack.IntType(32).unpack(getwork._swap4(ntime.decode('hex'))),
7171
bits=x['bits'],
7272
nonce=pack.IntType(32).unpack(getwork._swap4(nonce.decode('hex'))),

0 commit comments

Comments
 (0)