|
| 1 | +# Oracle golden generator for BCH G2 coinbase-author KAT. |
| 2 | +# Transcribes VERBATIM the v36 output-assembly from p2pool-merged-v36 |
| 3 | +# p2pool/data.py:920-1085 (generate_transaction, v36_active branch): |
| 4 | +# amounts = subsidy*weight//total_weight ; |
| 5 | +# total_donation = subsidy - sum(amounts) ; |
| 6 | +# if total_donation < 1 and subsidy>0: largest by (amount,script) -=1 ; recompute |
| 7 | +# amounts[DON] += total_donation |
| 8 | +# dests = sorted(scripts \ {DON}, key=(amounts[s], s))[-4000:] |
| 9 | +# payouts = [{value:amounts[s], script:s} for s in dests if amounts[s]] + [DON last] |
| 10 | +import struct |
| 11 | + |
| 12 | +COMBINED_DONATION_SCRIPT = bytes.fromhex('a9148c6272621d89e8fa526dd86acff60c7136be8e8587') |
| 13 | +def p2pkh(b): return bytes.fromhex('76a914') + bytes([b])*20 + bytes.fromhex('88ac') |
| 14 | +A=p2pkh(0xaa); B=p2pkh(0xbb); C=p2pkh(0xcc); D=p2pkh(0xdd) |
| 15 | + |
| 16 | +def assemble_v36(weights, donation_weight, subsidy): |
| 17 | + total_weight = sum(weights.values()) + donation_weight |
| 18 | + amounts = dict((s, subsidy*w//total_weight) for s,w in weights.items()) |
| 19 | + total_donation = subsidy - sum(amounts.values()) |
| 20 | + if total_donation < 1 and subsidy > 0: |
| 21 | + largest = max(amounts, key=lambda k:(amounts[k], k)) |
| 22 | + amounts[largest] -= 1 |
| 23 | + total_donation = subsidy - sum(amounts.values()) |
| 24 | + amounts[COMBINED_DONATION_SCRIPT] = amounts.get(COMBINED_DONATION_SCRIPT,0) + total_donation |
| 25 | + excluded = {COMBINED_DONATION_SCRIPT} |
| 26 | + dests = sorted([s for s in amounts if s not in excluded], key=lambda s:(amounts[s], s))[-4000:] |
| 27 | + payouts = [(s, amounts[s]) for s in dests if amounts[s]] |
| 28 | + payouts.append((COMBINED_DONATION_SCRIPT, amounts[COMBINED_DONATION_SCRIPT])) |
| 29 | + return payouts |
| 30 | + |
| 31 | +def assemble_with_finderfee(weights, finder, donation_weight, subsidy): |
| 32 | + # NEGATIVE control: pre-v36 math (199/200 haircut) + subsidy//200 finder fee. |
| 33 | + total_weight = sum(weights.values()) + donation_weight |
| 34 | + amounts = dict((s, subsidy*(199*w)//(200*total_weight)) for s,w in weights.items()) |
| 35 | + amounts[finder] = amounts.get(finder,0) + subsidy//200 |
| 36 | + total_donation = subsidy - sum(amounts.values()) |
| 37 | + if total_donation < 1 and subsidy > 0: |
| 38 | + largest = max(amounts, key=lambda k:(amounts[k], k)) |
| 39 | + amounts[largest] -= 1 |
| 40 | + total_donation = subsidy - sum(amounts.values()) |
| 41 | + amounts[COMBINED_DONATION_SCRIPT] = amounts.get(COMBINED_DONATION_SCRIPT,0) + total_donation |
| 42 | + dests = sorted([s for s in amounts if s != COMBINED_DONATION_SCRIPT], key=lambda s:(amounts[s], s))[-4000:] |
| 43 | + payouts = [(s, amounts[s]) for s in dests if amounts[s]] |
| 44 | + payouts.append((COMBINED_DONATION_SCRIPT, amounts[COMBINED_DONATION_SCRIPT])) |
| 45 | + return payouts |
| 46 | + |
| 47 | +def varint(n): |
| 48 | + if n < 0xfd: return bytes([n]) |
| 49 | + if n <= 0xffff: return b'\xfd'+struct.pack('<H',n) |
| 50 | + if n <= 0xffffffff: return b'\xfe'+struct.pack('<I',n) |
| 51 | + return b'\xff'+struct.pack('<Q',n) |
| 52 | + |
| 53 | +def serialize(payouts): |
| 54 | + out = b'' |
| 55 | + for script, value in payouts: |
| 56 | + out += struct.pack('<Q', value) + varint(len(script)) + script |
| 57 | + return out |
| 58 | + |
| 59 | +SUB = 1_000_000_000 |
| 60 | +cases = { |
| 61 | + 'CASE1_ordering_tie': assemble_v36({A:10,B:20,C:20,D:50}, 0, SUB), |
| 62 | + 'CASE2_donation_forced_last': assemble_v36({A:40,B:20}, 40, SUB), |
| 63 | + 'CASE3_v36_no_finderfee': assemble_v36({A:60,B:40}, 0, SUB), |
| 64 | + 'CASE3_NEG_with_finderfee': assemble_with_finderfee({A:60,B:40}, A, 0, SUB), |
| 65 | +} |
| 66 | +names = {A.hex():'A',B.hex():'B',C.hex():'C',D.hex():'D',COMBINED_DONATION_SCRIPT.hex():'DON'} |
| 67 | +for name, p in cases.items(): |
| 68 | + print('=== %s ===' % name) |
| 69 | + for s,v in p: print(' %-4s value=%d' % (names.get(s.hex(),'?'), v)) |
| 70 | + print(' OUTSECTION_HEX=%s' % serialize(p).hex()) |
0 commit comments