Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
chris-belcher opened this issue Apr 25, 2015 · 10 comments

Comments

@chris-belcher
Copy link

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
@chris-belcher chris-belcher changed the title non-mandatory-script-verify-flag Error when pushing tx made by pybitcointools [bug] non-mandatory-script-verify-flag Error when pushing tx made by pybitcointools Apr 26, 2015
@adlai
Copy link

adlai commented May 23, 2015

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

@wizardofozzie
Copy link
Contributor

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
Copy link
Author

Thanks for solving it @simcity4242
We're about to merge it into JoinMarket. JoinMarket-Org/joinmarket#167

@reiven
Copy link
Contributor

reiven commented Mar 15, 2016

Ping?

@adlai
Copy link

adlai commented Mar 16, 2016

pong

@reiven
Copy link
Contributor

reiven commented Jun 14, 2016

Spam on Github Issues!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants
@adlai @reiven @wizardofozzie @chris-belcher and others