I am using fourth chair adjustment logic to calculate miner reward for a given block. If miner can insert additional inputs in coinbase transaction and transaction outputs do not cover input value, it may be possible to generate negative mining reward and decrease bitcoin supply.
Revelant part of logic expressed in python 3 goes below. Variables data2jsonobject, requestrpcjobqueue, rpcsocketqueue, ipportpair, rpcauthpair are defined outside from this part of code. Last parameter pushed in requestrpcjobqueue returns a pair with status and raw data returned from bitcoin client.
transactioncountstatus = b'not processed'
transactioncount = b''
minerrewardstatus = b'not processed'
minerreward = b''
try:
coinbasetransactionid = data2jsonobject['result']['tx'][0].encode()
transactioncount = str(len(data2jsonobject['result']['tx'])).encode()
transactioncountstatus = b'ok'
coinbasetransactionhandle = queue.Queue()
requestrpcjobqueue.put((rpcsocketqueue, ipportpair, rpcauthpair, b'{"jsonrpc": "1.0", "method": "getrawtransaction", "params": ["' + coinbasetransactionid + b'", 1]}', coinbasetransactionhandle))
rpcstatus3, data3 = coinbasetransactionhandle.get()
if rpcstatus3 = b'received':
try:
data3jsonobject = json.loads(data3.decode())
txinput = data3jsonobject['result']['vin'][0]
txinputcount = len(data3jsonobject['result']['vin'])
k = 0
coinbaseinputstatus = b'not found'
coinbaseoutputvalue = 0
txoutput = data3jsonobject['result']['vout'][0]
txoutputcount = len(data3jsonobject['result']['vin'])
while k < txoutputcount:
coinbaseoutputvalue += data3jsonobject['result']['vin'][k]['value']
k += 1
k = 0
noncoinbaseinputvalue = 0
while k < txinputcount:
txinput = data3jsonobject['result']['vin'][k]
col84status = b'no failures'
try:
col88x = txinput['coinbase']
coinbaseinputstatus = b'found'
except KeyError:
col88txid = txinput['txid'].encode()
col88vout = str(txinput['vout']).encode()
col88handle = queue.Queue()
requestrpcjobqueue.put((rpcsocketqueue, ipportpair, rpcauthpair, b'{"jsonrpc": "1.0", "method": "getrawtransaction", "params": ["' + col88txid + b'", 1]}', col88handle))
col88rpcstatus, col88data = col88handle.get()
col88status = b'not processed'
if col88rpcstatus == b'received':
col92jsonobject = json.loads(col88data.decode())
col92count = len(col92jsonobject['result']['vout'])
col92i = 0
while col92i < col92count:
if str(col92jsonobject['result']['vout'][col92i]['n']).encode() == col88vout:
noncoinbaseinputvalue += col92jsonobject['result']['vout'][col92i]['value']
col88status = b'ok'
col92i += 1
if col88status != b'ok':
col84status = b'could not find transaction ' + col88txid + b' with output ' + col88vout
if col84status != b'no failures':
coinbaseinputstatus = col84status
break
k += 1
if coinbaseinputstatus == b'found':
minerreward = str(coinbaseoutputvalue - noncoinbaseinputvalue).encode()
minerrewardstatus = b'ok'
except json.decoder.JSONDecodeError:
minerrewardstatus = b'could not interpret rpc json response'
except KeyError:
minerrewardstatus = b'unexpected rpc json response structure'
try:
minerrewardstatus = b'rpc json error message: ' + json.loads(data3.decode())['error']['message'].encode()
except KeyError:
pass
except KeyError:
transactioncountstatus = b'unexpected rpc json response structure'
try:
transactioncountstatus = b'rpc json error message: ' + data2jsonobject['error']['message'].encode()
except KeyError:
pass