Skip to content

Commit

Permalink
Merge pull request #1 from veqtrus/segwit1+empty_block_fix1
Browse files Browse the repository at this point in the history
Segwit1+empty block fix1
  • Loading branch information
fflo authored Jul 29, 2017
2 parents 9429100 + f6a6ea0 commit 8c64043
Show file tree
Hide file tree
Showing 17 changed files with 361 additions and 438 deletions.
108 changes: 93 additions & 15 deletions p2pool/bitcoin/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,30 +91,87 @@ def write(self, file, item):
('port', pack.IntType(16, 'big')),
])

tx_type = pack.ComposedType([
('version', pack.IntType(32)),
('tx_ins', pack.ListType(pack.ComposedType([
('previous_output', pack.PossiblyNoneType(dict(hash=0, index=2**32 - 1), pack.ComposedType([
('hash', pack.IntType(256)),
('index', pack.IntType(32)),
]))),
('script', pack.VarStrType()),
('sequence', pack.PossiblyNoneType(2**32 - 1, pack.IntType(32))),
]))),
('tx_outs', pack.ListType(pack.ComposedType([
('value', pack.IntType(64)),
('script', pack.VarStrType()),
def is_segwit_tx(tx):
return tx.get('marker', -1) == 0 and tx.get('flag', -1) >= 1

tx_in_type = pack.ComposedType([
('previous_output', pack.PossiblyNoneType(dict(hash=0, index=2**32 - 1), pack.ComposedType([
('hash', pack.IntType(256)),
('index', pack.IntType(32)),
]))),
('lock_time', pack.IntType(32)),
('script', pack.VarStrType()),
('sequence', pack.PossiblyNoneType(2**32 - 1, pack.IntType(32))),
])

tx_out_type = pack.ComposedType([
('value', pack.IntType(64)),
('script', pack.VarStrType()),
])

tx_id_type = pack.ComposedType([
('version', pack.IntType(32)),
('tx_ins', pack.ListType(tx_in_type)),
('tx_outs', pack.ListType(tx_out_type)),
('lock_time', pack.IntType(32))
])

class TransactionType(pack.Type):
_int_type = pack.IntType(32)
_varint_type = pack.VarIntType()
_witness_type = pack.ListType(pack.VarStrType())
_wtx_type = pack.ComposedType([
('flag', pack.IntType(8)),
('tx_ins', pack.ListType(tx_in_type)),
('tx_outs', pack.ListType(tx_out_type))
])
_ntx_type = pack.ComposedType([
('tx_outs', pack.ListType(tx_out_type)),
('lock_time', _int_type)
])
_write_type = pack.ComposedType([
('version', _int_type),
('marker', pack.IntType(8)),
('flag', pack.IntType(8)),
('tx_ins', pack.ListType(tx_in_type)),
('tx_outs', pack.ListType(tx_out_type))
])

def read(self, file):
version, file = self._int_type.read(file)
marker, file = self._varint_type.read(file)
if marker == 0:
next, file = self._wtx_type.read(file)
witness = [None]*len(next['tx_ins'])
for i in xrange(len(next['tx_ins'])):
witness[i], file = self._witness_type.read(file)
locktime, file = self._int_type.read(file)
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
else:
tx_ins = [None]*marker
for i in xrange(marker):
tx_ins[i], file = tx_in_type.read(file)
next, file = self._ntx_type.read(file)
return dict(version=version, tx_ins=tx_ins, tx_outs=next['tx_outs'], lock_time=next['lock_time']), file

def write(self, file, item):
if is_segwit_tx(item):
assert len(item['tx_ins']) == len(item['witness'])
res = self._write_type.pack(item)
for w in item['witness']:
res += self._witness_type.pack(w)
res += self._int_type.pack(item['lock_time'])
return file, res
return tx_id_type.write(file, item)

tx_type = TransactionType()

merkle_link_type = pack.ComposedType([
('branch', pack.ListType(pack.IntType(256))),
('index', pack.IntType(32)),
])

merkle_tx_type = pack.ComposedType([
('tx', tx_type),
('tx', tx_id_type), # used only in aux_pow_type
('block_hash', pack.IntType(256)),
('merkle_link', merkle_link_type),
])
Expand All @@ -133,6 +190,11 @@ def write(self, file, item):
('txs', pack.ListType(tx_type)),
])

stripped_block_type = pack.ComposedType([
('header', block_header_type),
('txs', pack.ListType(tx_id_type)),
])

# merged mining

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

# transactions

def get_witness_commitment_hash(witness_root_hash, witness_reserved_value):
return hash256(merkle_record_type.pack(dict(left=witness_root_hash, right=witness_reserved_value)))

def get_wtxid(tx, txid=None, txhash=None):
has_witness = False
if is_segwit_tx(tx):
assert len(tx['tx_ins']) == len(tx['witness'])
has_witness = any(len(w) > 0 for w in tx['witness'])
if has_witness:
return hash256(tx_type.pack(tx)) if txhash is None else txhash
else:
return hash256(tx_id_type.pack(tx)) if txid is None else txid

def get_txid(tx):
return hash256(tx_id_type.pack(tx))

def pubkey_to_script2(pubkey):
assert len(pubkey) <= 75
return (chr(len(pubkey)) + pubkey) + '\xac'
Expand Down
7 changes: 5 additions & 2 deletions p2pool/bitcoin/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def check(bitcoind, net):
def getwork(bitcoind, use_getblocktemplate=False):
def go():
if use_getblocktemplate:
return bitcoind.rpc_getblocktemplate(dict(mode='template'))
return bitcoind.rpc_getblocktemplate(dict(mode='template', rules=['segwit']))
else:
return bitcoind.rpc_getmemorypool()
try:
Expand Down Expand Up @@ -71,6 +71,7 @@ def go():
bits=bitcoin_data.FloatingIntegerType().unpack(work['bits'].decode('hex')[::-1]) if isinstance(work['bits'], (str, unicode)) else bitcoin_data.FloatingInteger(work['bits']),
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 '',
height=work['height'],
rules=work.get('rules', []),
last_update=time.time(),
use_getblocktemplate=use_getblocktemplate,
latency=end - start,
Expand All @@ -86,9 +87,11 @@ def submit_block_p2p(block, factory, net):
@deferral.retry('Error submitting block: (will retry)', 10, 10)
@defer.inlineCallbacks
def submit_block_rpc(block, ignore_failure, bitcoind, bitcoind_work, net):
segwit_rules = set(['!segwit', 'segwit'])
segwit_activated = len(segwit_rules - set(bitcoind_work.value['rules'])) < len(segwit_rules)
if bitcoind_work.value['use_getblocktemplate']:
try:
result = yield bitcoind.rpc_submitblock(bitcoin_data.block_type.pack(block).encode('hex'))
result = yield bitcoind.rpc_submitblock((bitcoin_data.block_type if segwit_activated else bitcoin_data.stripped_block_type).pack(block).encode('hex'))
except jsonrpc.Error_for_code(-32601): # Method not found, for older litecoin versions
result = yield bitcoind.rpc_getblocktemplate(dict(mode='submit', data=bitcoin_data.block_type.pack(block).encode('hex')))
success = result is None
Expand Down
27 changes: 27 additions & 0 deletions p2pool/bitcoin/networks/btcregtest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import os
import platform

from twisted.internet import defer

from .. import data, helper
from p2pool.util import pack


P2P_PREFIX = 'fabfb5da'.decode('hex')
P2P_PORT = 18444
ADDRESS_VERSION = 111
RPC_PORT = 28332
RPC_CHECK = defer.inlineCallbacks(lambda bitcoind: defer.returnValue(
'bitcoinaddress' in (yield bitcoind.rpc_help())
))
SUBSIDY_FUNC = lambda height: 50*100000000 >> (height + 1)//150
POW_FUNC = data.hash256
BLOCK_PERIOD = 600 # s
SYMBOL = 'rBTC'
CONF_FILE_FUNC = lambda: os.path.join(os.path.join(os.environ['APPDATA'], 'Bitcoin') if platform.system() == 'Windows' else os.path.expanduser('~/Library/Application Support/Bitcoin/') if platform.system() == 'Darwin' else os.path.expanduser('~/.bitcoin'), 'bitcoin.conf')
BLOCK_EXPLORER_URL_PREFIX = '#'
ADDRESS_EXPLORER_URL_PREFIX = '#'
TX_EXPLORER_URL_PREFIX = '#'
SANE_TARGET_RANGE = (2**256//2**32//1000 - 1, 2**256//2 - 1)
DUMB_SCRYPT_DIFF = 1
DUST_THRESHOLD = 1e8
10 changes: 10 additions & 0 deletions p2pool/bitcoin/p2p.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ def handle_pong(self, nonce):
])
def handle_alert(self, message, signature):
pass # print 'ALERT:', (message, signature)

message_reject = pack.ComposedType([
('message', pack.VarStrType()),
('ccode', pack.IntType(8)),
('reason', pack.VarStrType()),
('data', pack.IntType(256)),
])
def handle_reject(self, message, ccode, reason, data):
if p2pool.DEBUG:
print >>sys.stderr, 'Received reject message (%s): %s' % (message, reason)

def connectionLost(self, reason):
if hasattr(self.factory, 'gotConnection'):
Expand Down
2 changes: 1 addition & 1 deletion p2pool/bitcoin/stratum.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def rpc_submit(self, worker_name, job_id, extranonce2, ntime, nonce):
header = dict(
version=x['version'],
previous_block=x['previous_block'],
merkle_root=bitcoin_data.check_merkle_link(bitcoin_data.hash256(new_packed_gentx), x['merkle_link']),
merkle_root=bitcoin_data.check_merkle_link(bitcoin_data.hash256(new_packed_gentx), x['merkle_link']), # new_packed_gentx has witness data stripped
timestamp=pack.IntType(32).unpack(getwork._swap4(ntime.decode('hex'))),
bits=x['bits'],
nonce=pack.IntType(32).unpack(getwork._swap4(nonce.decode('hex'))),
Expand Down
Loading

0 comments on commit 8c64043

Please sign in to comment.