vbuterin / pybitcointools

SImple, common-sense Bitcoin-themed Python ECC library
1.28k stars 857 forks source link

[bug] non-mandatory-script-verify-flag Error when pushing tx made by pybitcointools #89

Open chris-belcher opened 9 years ago

chris-belcher commented 9 years ago

Here is code that reproduces the tx. It is a regtest tx, I could upload my regtest/ directory if required.

import bitcoin as btc

tx_5825 = '0100000005980022ce9350f563cedb70ff576d8b8e0fa8cf9a0ee4760d36e428c91570a812010000006c493046022100adc9b9cab0a2428d1f38d4f922675a9ee3db2c9f85ea070ea484dc79f8d01fa0022100a885fa8753dc31fafbd98896e3cf3e3345b8f3c8acd42b3ff9bee65959c5171c012102107122bb8ade89244937faf7439b4d0f1812384eadec3a35b7903d0660d3d479ffffffffc8e66bf3cdb1f0798f3cc8c5b435b2c6bfced202dd9bfc68f8a82d427f0f2bee050000006b483045022100dd256287ba9f16ff1dfb35423d2af36de016ad6cb869d5415bc01ea400761a90022052245a970da2f9a3ac43ecc1ee84192000558b605d7614c39af10819d13da657012102230beb1b5745e9b9b6dba98f541857831db2aa0580472ee4ce3df05bc441be72ffffffff13a0e0f98ec6a99623ee198fa9ed4b49c03b3900fddebadadc6dc1b79a5fd2ba040000006c493046022100d3e36382c81a8ff454e06c4cb69fe7648ca28ceeb480f8100237953e76e215b9022100b40ea51b19f8015829388570bb776369a016e2311171ed1242ffb6fb069d5cb301210277129b6fe03e7c84f7406048d41e1622a741a2237d2b3edaf46e28cee344b652ffffffff980022ce9350f563cedb70ff576d8b8e0fa8cf9a0ee4760d36e428c91570a812020000006c493046022100fabb8c10886df0c2a2106f32c5731f39e05aec16de809e6d1ae800e8f4019368022100d53d353c5e47956b346fe7d66a81356dc01523149545c3e1b6f47d62bfd8c9b00121023d73a29015b383b3e7a3d3baff9f35fde1d81d2e9accaca3e6bc762f2df11a55ffffffffc8e66bf3cdb1f0798f3cc8c5b435b2c6bfced202dd9bfc68f8a82d427f0f2bee030000006a4730440220381f2849650e9875c65c424faf82631a107d9e5be6cb626a728494cb22b4606f02205c86c445ba20c726ffa4e5376f93c52524459180c9e6ff5d9a7a4f7fe84c8b96012103143a65e23bfc156051863b5c371a338b5f976914d43bfea5313b50438cbed942ffffffff0694123695000000001976a91444e13e5b04431526de0a4945e117583ec899810f88acfa90941b000000001976a91458691d41de22d2b5286039d176baae3d3c785e0f88aceeace61d000000001976a9141422800fb5c930770cddf4c7d6e7fb9fe710561288ac1ddda74c000000001976a914dc8af008230314ce43d56ed9326f047b710ae3fe88ac94123695000000001976a914d09bdcd91a15c9fec88849b7927ac1da501b116e88ac94123695000000001976a914b3c80951bc43b9265c0e27a94b49c5aa8520965788ac00000000'
assert btc.txhash(tx_5825) == '5825c725a2927c4d1d74e6d3676621f6ef6954bf95fe4fe6e0c4e8dd0346c0c6'

tx_12a8 = '0100000005c8e66bf3cdb1f0798f3cc8c5b435b2c6bfced202dd9bfc68f8a82d427f0f2bee000000006b48304502200f9087864888795d2d4ee1c3e049f8a3af633a3dcb2f8ddadf73280add1a3a43022100f48f5f2cb6d0a527dad4cb8df041e517d8198664145ced41592a0f48f9a8f72c01210305405f91840a4de707a4412464b421cd317669fb24ecfe8defea749a8bc2e327ffffffffe7d164b847d2ac9e5e98d66ad2c43e2a3d7e66ae4c55edc9a40824c6dcc9f0b4050000006b48304502203ffc9d25983fe2c56aeaaa34db4143dc796124b2b2c45b12c58b92c910758d70022100ccaf79fd20e503aef81e32610d30980a309a92c48b6a5b2788720fd17dfcb285012102b05b4db8671926c6a15c61bc12afdc1aa8ef37b1cc34d0bbe1d2446c4269ab6affffffff1f0028fd48f21b4b15e9aee450b93492bc1061376787873a06364932104eeb69010000006a47304402204b57ab03dfa628e6dab74ddcf53e9113a94d937323d304301f00513da4f56b65022070ea9dfbc5bed783f7616c73bf1129709f6d1c1a9c4a050a7ac71e5e44a4a8e0012103e950eff043e00a70b1c01ac5a03d4157bae72d129491581688ac65e30e4ba90dffffffff13a0e0f98ec6a99623ee198fa9ed4b49c03b3900fddebadadc6dc1b79a5fd2ba000000006c493046022100c69382b3cda3ad7bffbeda1036765a7f35cf648f1fe40660ca412cf093a4c876022100891010309060e61f0c5c9121c806ed37632dd3a9d7200c41adea0abaf7e2bc9501210286264ae391bf00604324df057023825d2d3025d5e23d222fdba2d3fa9bfabb8fffffffffe7d164b847d2ac9e5e98d66ad2c43e2a3d7e66ae4c55edc9a40824c6dcc9f0b4020000006a47304402200889c1da5a16fd100d199d2eb56cc1da83108304660341168f4bdce2e064dad602203889db9e656d5a41bf794babcfb138238489998f748170fc2bad3043fee77e070121022bb2ebb6899c94a88485027b1bad895992fd140d8014deb41463d4acdc7adc15ffffffff056de6ee1f000000001976a9144ce46664ba73e37d562ec3e76b0c9d9a9d3ec7df88ac15cf6d88000000001976a91444b76e75bb518ef157a81ddd552490534db5019788ac15cf6d88000000001976a914e8b808ce72a372c317e5bc517adc28307a89794f88ac15cf6d88000000001976a9143c72bbcb650c88b3b5ae27802af31fb6ecec4ba688ac9f166f19010000001976a9144232e272e40aabf25abc8579bf8a63913e71095c88ac00000000'
assert btc.txhash(tx_12a8) == '12a87015c928e4360d76e40e9acfa80f8e8b6d57ff70dbce63f55093ce220098'

utxo_privkeys = [
('5825c725a2927c4d1d74e6d3676621f6ef6954bf95fe4fe6e0c4e8dd0346c0c6:4', 'cUAZZEcHoDxTc4wMV2KNRmAAzMZGNPG6sjBcyab1UsdhBmiByLSf'),
('5825c725a2927c4d1d74e6d3676621f6ef6954bf95fe4fe6e0c4e8dd0346c0c6:0', 'cR4cSNZ1uDNrcK7ySiih5yC3YTLYg9ep2qVkgt92ptEjeT9jgmcm'),
('5825c725a2927c4d1d74e6d3676621f6ef6954bf95fe4fe6e0c4e8dd0346c0c6:5', 'cSz44CEnPK8f9un19y9AbPWoh2AwYYzTknMNNwkvXjbtEsW7SMdC'),
('12a87015c928e4360d76e40e9acfa80f8e8b6d57ff70dbce63f55093ce220098:3', 'cV4qW8AZsyTpCRdeaxY7qvAegmC55Peio2eyc2dpkqw5SFQ8fhQk')
]

outputs = \
[{'address': 'myD3VAt8nFUPTH4ppRrjmtvBZFqn734gfz', 'value': 1114147350},
 {'address': 'mvZB2DF1yD99uScKCwPtgCor6egsdiEXrL', 'value': 1114147350},
 {'address': 'mv53HA1roXE36XL7w9n22uogQy3vwWQWNH', 'value': 899696279},
 {'address': 'mwxD3Lw7LZbjyuVdTWFyB7S2dihQqy3WEj', 'value': 1391984503},
 {'address': 'n1CeSEDjUm7AJdAAzfAxdLPN3UCDQBAdK4', 'value': 1103002474},
 {'address': 'mvkKgMi5yXBdUyisqp4jFWffYZ6R3uWEtp', 'value': 1391984503},
 {'address': 'mfZhBrJJFS3YjsUcYncRDDAwcJxqxtBYRe', 'value': 1391984503},
 {'address': 'mjzNa9UDJvtMQZHfjxWHVik2DK9AWYcsMq', 'value': 1391984503}]

inputs = [{'output': up[0]} for up in utxo_privkeys]
tx = btc.mktx(inputs, outputs)

for i, up in enumerate(utxo_privkeys):
    tx = btc.sign(tx, i, up[1])
print tx

def getrawtransaction(txid):
    if txid.startswith('5825'):
        return tx_5825
    elif txid.startswith('12a8'):
        return tx_12a8
    else:
        return None

txd = btc.deserialize(tx)
for index, ins in enumerate(txd['ins']):
    rawtx = getrawtransaction(ins['outpoint']['hash'])
    script = btc.deserialize(rawtx)['outs'][ins['outpoint']['index']]['script']
    scriptPubKey = btc.deserialize_script(ins['script'])
    good = btc.verify_tx_input(tx, index, script, *scriptPubKey)
    print 'checking signature at ' + str(index) + ', Result = ' + str(good)

When run

0100000004c6c04603dde8c4e0e64ffe95bf5469eff6216667d3e6741d4d7c92a225c72558040000006c493046022100e1153d33e20a2203a379883ed8be9d0155b102fe5d26d0b2fd89ba3cfb3ba454022100ce227b56b6b13ff286e37820d2818410da92c7e9cbb5ef10c8e4793a68148a9e01210312a3424c47dd9cc87e50ae0f9993f4811fb84e80fa8b6f2cfedff144a01c94dfffffffffc6c04603dde8c4e0e64ffe95bf5469eff6216667d3e6741d4d7c92a225c72558000000006b483045022100a6c451d63e5124e9df678afdbadbb114c668b7a56746b9f2910a3de43ef5c525022020ffb275a2d822fad5ba172bf00d75402c68917ec28049c4106710baac196dc60121034fbd40b92050b64e7c057fe70bf002974263cc349c3a0916b9957bc8b26a03c8ffffffffc6c04603dde8c4e0e64ffe95bf5469eff6216667d3e6741d4d7c92a225c72558050000006b483045022100cfe66a9d9dc11a4c9e4dc3de29105acf0389c8467ae7117d12a323a25684833c0220053f3710665c91abf75f0fc5cf63898136f71d26d93b182afcdcb18519c048af012103ddaeea8b3d37ad6ab4935f1b23caf4eefbb5640a9fddcf8caa542620d10e82caffffffff980022ce9350f563cedb70ff576d8b8e0fa8cf9a0ee4760d36e428c91570a812030000006a473044021fc91b83d94f954146b0959ec4bdd00a1cd3ae48177aee6563e0a740324ae2d602210098f4519d5374b4eca68581b83b04f28cadd9ef967b7f139159195bec2057663e012103b824e91bbdb70b4672a07045e0b12d5f9ce7735aaac67a96f1a8ff8206394686ffffffff08168a6842000000001976a914c20f1c4f80661e2718d5bbf10a5c0a64b640a8e588ac168a6842000000001976a914a4f557afe46d42da29915bb62a9f53709fa7329088ac9746a035000000001976a9149fa33b8ce8071c4316c08ebdfe666113ce53db2788ac77fff752000000001976a914b448b8a3cd71322584003bfde55c306e46b4f64d88ac6a7bbe41000000001976a914d7ec1ed0cf25ab1d66797bb1c58c76e7284c51d088ac77fff752000000001976a914a711252aac3f5e57500aab8ef52435bb43222d7588ac77fff752000000001976a9140084a321f0a8abbfce767e77e0dcb6c112c5f9a188ac77fff752000000001976a914310ffff9ff4f815b262629982d7f34ae9a31686288ac00000000
checking signature at 0, Result = True
checking signature at 1, Result = True
checking signature at 2, Result = True
checking signature at 3, Result = True

Using sendrawtransaction on bitcoin core console produces this error

64: non-mandatory-script-verify-flag (No error) (code -26)

The relevant line the debug.log

2015-04-25 19:44:39 ERROR: CScriptCheck(): 951a38b33df011e92584deed5e67ce57ab9a0c1dba9e3c4b97fcb1cb4734a0ce:3 VerifySignature failed: Non-canonical DER signature
adlai commented 9 years ago

petertodd/python-bitcoinlib@f6e8dc9 fixes the same bug in a similar library

wizardofozzie commented 8 years ago

I've solved this issue so low s is always signed: see my pybitcointools fork

In transaction.py, der_encode_sig should:

  1. Check s value: s = N-s if s>N//2 else s
  2. Check that 1st byte for r and s is not greater than 0x7f, otherwise add a nullbyte (currently code only checks >= 2**255
def der_encode_sig(v, r, s):
    """Takes (vbyte, r, s) as ints and returns hex der encode sig"""
    s = N-s if s>N//2 else s    # BIP62 low s
    b1, b2 = encode(r, 256), encode(s, 256)
    if bytearray(b1)[0] & 0x80:     # add null bytes if leading byte interpreted as negative
        b1 = b'\x00' + b1
    if bytearray(b2)[0] & 0x80:
        b2 = b'\x00' + b2
    left  = b'\x02' + encode(len(b1), 256, 1) + b1
    right = b'\x02' + encode(len(b2), 256, 1) + b2
    sighex = safe_hexlify(b'\x30' + encode(len(left+right), 256, 1) + left + right)
    # check BIP66, see https://github.com/simcity4242/pybitcointools/blob/master/bitcoin/transaction.py#L181-L204
    assert is_bip66(sighex) 
    return sighex
chris-belcher commented 8 years ago

Thanks for solving it @simcity4242 We're about to merge it into JoinMarket. https://github.com/chris-belcher/joinmarket/pull/167

reiven commented 8 years ago

Ping?

adlai commented 8 years ago

pong

reiven commented 8 years ago

Spam on Github Issues!