3 # Electrum - lightweight Bitcoin client
4 # Copyright (C) 2011 thomasv@gitorious
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 # Note: The deserialization code originally comes from ABE.
24 from util
import print_error
29 # Workalike python implementation of Bitcoin's CDataStream class.
35 class SerializationError(Exception):
36 """ Thrown when there's a problem deserializing or serializing """
38 class BCDataStream(object):
47 def write(self
, bytes
): # Initialize with string of bytes
48 if self
.input is None:
53 def map_file(self
, file, start
): # Initialize with bytes from file
54 self
.input = mmap
.mmap(file.fileno(), 0, access
=mmap
.ACCESS_READ
)
55 self
.read_cursor
= start
57 def seek_file(self
, position
):
58 self
.read_cursor
= position
63 def read_string(self
):
64 # Strings are encoded depending on length:
65 # 0 to 252 : 1-byte-length followed by bytes (if any)
66 # 253 to 65,535 : byte'253' 2-byte-length followed by bytes
67 # 65,536 to 4,294,967,295 : byte '254' 4-byte-length followed by bytes
68 # ... and the Bitcoin client is coded to understand:
69 # greater than 4,294,967,295 : byte '255' 8-byte-length followed by bytes of string
70 # ... but I don't think it actually handles any strings that big.
71 if self
.input is None:
72 raise SerializationError("call write(bytes) before trying to deserialize")
75 length
= self
.read_compact_size()
77 raise SerializationError("attempt to read past end of buffer")
79 return self
.read_bytes(length
)
81 def write_string(self
, string
):
82 # Length-encoded as with read-string
83 self
.write_compact_size(len(string
))
86 def read_bytes(self
, length
):
88 result
= self
.input[self
.read_cursor
:self
.read_cursor
+length
]
89 self
.read_cursor
+= length
92 raise SerializationError("attempt to read past end of buffer")
96 def read_boolean(self
): return self
.read_bytes(1)[0] != chr(0)
97 def read_int16(self
): return self
._read
_num
('<h')
98 def read_uint16(self
): return self
._read
_num
('<H')
99 def read_int32(self
): return self
._read
_num
('<i')
100 def read_uint32(self
): return self
._read
_num
('<I')
101 def read_int64(self
): return self
._read
_num
('<q')
102 def read_uint64(self
): return self
._read
_num
('<Q')
104 def write_boolean(self
, val
): return self
.write(chr(1) if val
else chr(0))
105 def write_int16(self
, val
): return self
._write
_num
('<h', val
)
106 def write_uint16(self
, val
): return self
._write
_num
('<H', val
)
107 def write_int32(self
, val
): return self
._write
_num
('<i', val
)
108 def write_uint32(self
, val
): return self
._write
_num
('<I', val
)
109 def write_int64(self
, val
): return self
._write
_num
('<q', val
)
110 def write_uint64(self
, val
): return self
._write
_num
('<Q', val
)
112 def read_compact_size(self
):
113 size
= ord(self
.input[self
.read_cursor
])
114 self
.read_cursor
+= 1
116 size
= self
._read
_num
('<H')
118 size
= self
._read
_num
('<I')
120 size
= self
._read
_num
('<Q')
123 def write_compact_size(self
, size
):
125 raise SerializationError("attempt to write size < 0")
127 self
.write(chr(size
))
130 self
._write
_num
('<H', size
)
133 self
._write
_num
('<I', size
)
136 self
._write
_num
('<Q', size
)
138 def _read_num(self
, format
):
139 (i
,) = struct
.unpack_from(format
, self
.input, self
.read_cursor
)
140 self
.read_cursor
+= struct
.calcsize(format
)
143 def _write_num(self
, format
, num
):
144 s
= struct
.pack(format
, num
)
149 # From the Python Cookbook, downloaded from http://code.activestate.com/recipes/67107/
151 import types
, string
, exceptions
153 class EnumException(exceptions
.Exception):
157 def __init__(self
, name
, enumList
):
165 if type(x
) == types
.TupleType
:
167 if type(x
) != types
.StringType
:
168 raise EnumException
, "enum name is not a string: " + x
169 if type(i
) != types
.IntType
:
170 raise EnumException
, "enum value is not an integer: " + i
172 raise EnumException
, "enum name is not unique: " + x
173 if i
in uniqueValues
:
174 raise EnumException
, "enum value is not unique for " + x
175 uniqueNames
.append(x
)
176 uniqueValues
.append(i
)
181 self
.reverseLookup
= reverseLookup
182 def __getattr__(self
, attr
):
183 if not self
.lookup
.has_key(attr
):
185 return self
.lookup
[attr
]
186 def whatis(self
, value
):
187 return self
.reverseLookup
[value
]
190 # This function comes from bitcointools, bct-LICENSE.txt.
192 return bytes
.encode('hex_codec')
194 # This function comes from bitcointools, bct-LICENSE.txt.
195 def short_hex(bytes
):
196 t
= bytes
.encode('hex_codec')
199 return t
[0:4]+"..."+t
[-4:]
204 def parse_redeemScript(bytes
):
205 dec
= [ x
for x
in script_GetOp(bytes
.decode('hex')) ]
208 match
= [ opcodes
.OP_2
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_2
, opcodes
.OP_CHECKMULTISIG
]
209 if match_decoded(dec
, match
):
210 pubkeys
= [ dec
[1][1].encode('hex'), dec
[2][1].encode('hex') ]
214 match
= [ opcodes
.OP_2
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_3
, opcodes
.OP_CHECKMULTISIG
]
215 if match_decoded(dec
, match
):
216 pubkeys
= [ dec
[1][1].encode('hex'), dec
[2][1].encode('hex'), dec
[3][1].encode('hex') ]
221 opcodes
= Enumeration("Opcodes", [
222 ("OP_0", 0), ("OP_PUSHDATA1",76), "OP_PUSHDATA2", "OP_PUSHDATA4", "OP_1NEGATE", "OP_RESERVED",
223 "OP_1", "OP_2", "OP_3", "OP_4", "OP_5", "OP_6", "OP_7",
224 "OP_8", "OP_9", "OP_10", "OP_11", "OP_12", "OP_13", "OP_14", "OP_15", "OP_16",
225 "OP_NOP", "OP_VER", "OP_IF", "OP_NOTIF", "OP_VERIF", "OP_VERNOTIF", "OP_ELSE", "OP_ENDIF", "OP_VERIFY",
226 "OP_RETURN", "OP_TOALTSTACK", "OP_FROMALTSTACK", "OP_2DROP", "OP_2DUP", "OP_3DUP", "OP_2OVER", "OP_2ROT", "OP_2SWAP",
227 "OP_IFDUP", "OP_DEPTH", "OP_DROP", "OP_DUP", "OP_NIP", "OP_OVER", "OP_PICK", "OP_ROLL", "OP_ROT",
228 "OP_SWAP", "OP_TUCK", "OP_CAT", "OP_SUBSTR", "OP_LEFT", "OP_RIGHT", "OP_SIZE", "OP_INVERT", "OP_AND",
229 "OP_OR", "OP_XOR", "OP_EQUAL", "OP_EQUALVERIFY", "OP_RESERVED1", "OP_RESERVED2", "OP_1ADD", "OP_1SUB", "OP_2MUL",
230 "OP_2DIV", "OP_NEGATE", "OP_ABS", "OP_NOT", "OP_0NOTEQUAL", "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV",
231 "OP_MOD", "OP_LSHIFT", "OP_RSHIFT", "OP_BOOLAND", "OP_BOOLOR",
232 "OP_NUMEQUAL", "OP_NUMEQUALVERIFY", "OP_NUMNOTEQUAL", "OP_LESSTHAN",
233 "OP_GREATERTHAN", "OP_LESSTHANOREQUAL", "OP_GREATERTHANOREQUAL", "OP_MIN", "OP_MAX",
234 "OP_WITHIN", "OP_RIPEMD160", "OP_SHA1", "OP_SHA256", "OP_HASH160",
235 "OP_HASH256", "OP_CODESEPARATOR", "OP_CHECKSIG", "OP_CHECKSIGVERIFY", "OP_CHECKMULTISIG",
236 "OP_CHECKMULTISIGVERIFY",
237 ("OP_SINGLEBYTE_END", 0xF0),
238 ("OP_DOUBLEBYTE_BEGIN", 0xF000),
239 "OP_PUBKEY", "OP_PUBKEYHASH",
240 ("OP_INVALIDOPCODE", 0xFFFF),
244 def script_GetOp(bytes
):
246 while i
< len(bytes
):
248 opcode
= ord(bytes
[i
])
250 if opcode
>= opcodes
.OP_SINGLEBYTE_END
:
252 opcode |
= ord(bytes
[i
])
255 if opcode
<= opcodes
.OP_PUSHDATA4
:
257 if opcode
== opcodes
.OP_PUSHDATA1
:
258 nSize
= ord(bytes
[i
])
260 elif opcode
== opcodes
.OP_PUSHDATA2
:
261 (nSize
,) = struct
.unpack_from('<H', bytes
, i
)
263 elif opcode
== opcodes
.OP_PUSHDATA4
:
264 (nSize
,) = struct
.unpack_from('<I', bytes
, i
)
266 vch
= bytes
[i
:i
+nSize
]
269 yield (opcode
, vch
, i
)
272 def script_GetOpName(opcode
):
273 return (opcodes
.whatis(opcode
)).replace("OP_", "")
276 def decode_script(bytes
):
278 for (opcode
, vch
, i
) in script_GetOp(bytes
):
279 if len(result
) > 0: result
+= " "
280 if opcode
<= opcodes
.OP_PUSHDATA4
:
281 result
+= "%d:"%(opcode
,)
282 result
+= short_hex(vch
)
284 result
+= script_GetOpName(opcode
)
288 def match_decoded(decoded
, to_match
):
289 if len(decoded
) != len(to_match
):
291 for i
in range(len(decoded
)):
292 if to_match
[i
] == opcodes
.OP_PUSHDATA4
and decoded
[i
][0] <= opcodes
.OP_PUSHDATA4
and decoded
[i
][0]>0:
293 continue # Opcodes below OP_PUSHDATA4 all just push data onto stack, and are equivalent.
294 if to_match
[i
] != decoded
[i
][0]:
298 def parse_scriptSig(d
, bytes
):
300 decoded
= [ x
for x
in script_GetOp(bytes
) ]
302 # coinbase transactions raise an exception
303 print_error("cannot find address in input script", bytes
.encode('hex'))
307 match
= [ opcodes
.OP_PUSHDATA4
]
308 if match_decoded(decoded
, match
):
311 # non-generated TxIn transactions push a signature
312 # (seventy-something bytes) and then their public key
313 # (65 bytes) onto the stack:
314 match
= [ opcodes
.OP_PUSHDATA4
, opcodes
.OP_PUSHDATA4
]
315 if match_decoded(decoded
, match
):
316 sig
= decoded
[0][1].encode('hex')
317 pubkey
= decoded
[1][1].encode('hex')
320 d
['pubkeys'] = [pubkey
]
321 d
['signatures'] = {pubkey
:sig
}
322 d
['address'] = public_key_to_bc_address(pubkey
.decode('hex'))
325 print_error("cannot find address in input script", bytes
.encode('hex'))
328 # p2sh transaction, 2 of n
329 match
= [ opcodes
.OP_0
]
330 while len(match
) < len(decoded
):
331 match
.append(opcodes
.OP_PUSHDATA4
)
333 if match_decoded(decoded
, match
):
334 redeemScript
= decoded
[-1][1]
336 d
['signatures'] = map(lambda x
:x
[1][:-1].encode('hex'), decoded
[1:-1])
337 d
['address'] = hash_160_to_bc_address(hash_160(redeemScript
), 5)
338 d
['redeemScript'] = redeemScript
.encode('hex')
339 dec2
= [ x
for x
in script_GetOp(redeemScript
) ]
340 match_2of2
= [ opcodes
.OP_2
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_2
, opcodes
.OP_CHECKMULTISIG
]
341 match_2of3
= [ opcodes
.OP_2
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_3
, opcodes
.OP_CHECKMULTISIG
]
342 if match_decoded(dec2
, match_2of2
):
343 pubkeys
= [ dec2
[1][1].encode('hex'), dec2
[2][1].encode('hex') ]
344 elif match_decoded(dec2
, match_2of3
):
345 pubkeys
= [ dec2
[1][1].encode('hex'), dec2
[2][1].encode('hex'), dec2
[3][1].encode('hex') ]
348 d
['pubkeys'] = pubkeys
351 print_error("cannot find address in input script", bytes
.encode('hex'))
356 def get_address_from_output_script(bytes
):
357 decoded
= [ x
for x
in script_GetOp(bytes
) ]
359 # The Genesis Block, self-payments, and pay-by-IP-address payments look like:
360 # 65 BYTES:... CHECKSIG
361 match
= [ opcodes
.OP_PUSHDATA4
, opcodes
.OP_CHECKSIG
]
362 if match_decoded(decoded
, match
):
363 return True, public_key_to_bc_address(decoded
[0][1])
365 # Pay-by-Bitcoin-address TxOuts look like:
366 # DUP HASH160 20 BYTES:... EQUALVERIFY CHECKSIG
367 match
= [ opcodes
.OP_DUP
, opcodes
.OP_HASH160
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_EQUALVERIFY
, opcodes
.OP_CHECKSIG
]
368 if match_decoded(decoded
, match
):
369 return False, hash_160_to_bc_address(decoded
[2][1])
372 match
= [ opcodes
.OP_HASH160
, opcodes
.OP_PUSHDATA4
, opcodes
.OP_EQUAL
]
373 if match_decoded(decoded
, match
):
374 return False, hash_160_to_bc_address(decoded
[1][1],5)
376 return False, "(None)"
381 def __init__(self
, raw
):
384 self
.inputs
= self
.d
['inputs']
385 self
.outputs
= self
.d
['outputs']
386 self
.outputs
= map(lambda x
: (x
['address'],x
['value']), self
.outputs
)
387 self
.locktime
= self
.d
['lockTime']
393 def from_io(klass
, inputs
, outputs
):
394 raw
= klass
.serialize(inputs
, outputs
, for_sig
= None) # for_sig=-1 means do not sign
397 self
.outputs
= outputs
401 def sweep(klass
, privkeys
, network
, to_address
, fee
):
403 for privkey
in privkeys
:
404 pubkey
= public_key_from_private_key(privkey
)
405 address
= address_from_private_key(privkey
)
406 u
= network
.synchronous_get([ ('blockchain.address.listunspent',[address
])])[0]
407 pay_script
= klass
.pay_script(address
)
409 item
['scriptPubKey'] = pay_script
410 item
['redeemPubkey'] = pubkey
411 item
['address'] = address
412 item
['prevout_hash'] = item
['tx_hash']
413 item
['prevout_n'] = item
['tx_pos']
419 total
= sum( map(lambda x
:int(x
.get('value')), inputs
) ) - fee
420 outputs
= [(to_address
, total
)]
421 self
= klass
.from_io(inputs
, outputs
)
422 self
.sign({ pubkey
:privkey
})
426 def multisig_script(klass
, public_keys
, num
=None):
428 if num
is None: num
= n
429 # supports only "2 of 2", and "2 of 3" transactions
430 assert num
<= n
and n
in [2,3]
439 for k
in public_keys
:
440 s
+= var_int(len(k
)/2)
454 def pay_script(self
, addr
):
455 addrtype
, hash_160
= bc_address_to_hash_160(addr
)
457 script
= '76a9' # op_dup, op_hash_160
458 script
+= '14' # push 0x14 bytes
459 script
+= hash_160
.encode('hex')
460 script
+= '88ac' # op_equalverify, op_checksig
462 script
= 'a9' # op_hash_160
463 script
+= '14' # push 0x14 bytes
464 script
+= hash_160
.encode('hex')
465 script
+= '87' # op_equal
472 def serialize( klass
, inputs
, outputs
, for_sig
= None ):
474 push_script
= lambda x
: op_push(len(x
)/2) + x
475 s
= int_to_hex(1,4) # version
476 s
+= var_int( len(inputs
) ) # number of inputs
477 for i
in range(len(inputs
)):
479 s
+= txin
['prevout_hash'].decode('hex')[::-1].encode('hex') # prev hash
480 s
+= int_to_hex(txin
['prevout_n'],4) # prev index
482 signatures
= txin
.get('signatures', {})
483 if for_sig
is None and not signatures
:
486 elif for_sig
is None:
487 pubkeys
= txin
['pubkeys']
489 for pubkey
in pubkeys
:
490 sig
= signatures
.get(pubkey
)
494 sig_list
+= push_script(sig
)
496 if not txin
.get('redeemScript'):
498 script
+= push_script(pubkeys
[0])
502 redeem_script
= klass
.multisig_script(pubkeys
,2)
503 assert redeem_script
== txin
.get('redeemScript')
504 script
+= push_script(redeem_script
)
507 if txin
.get('redeemScript'):
508 script
= txin
['redeemScript'] # p2sh uses the inner script
510 script
= txin
['scriptPubKey'] # scriptsig
513 s
+= var_int( len(script
)/2 ) # script length
515 s
+= "ffffffff" # sequence
517 s
+= var_int( len(outputs
) ) # number of outputs
518 for output
in outputs
:
519 addr
, amount
= output
520 s
+= int_to_hex( amount
, 8) # amount
521 script
= klass
.pay_script(addr
)
522 s
+= var_int( len(script
)/2 ) # script length
524 s
+= int_to_hex(0,4) # lock time
525 if for_sig
is not None and for_sig
!= -1:
526 s
+= int_to_hex(1, 4) # hash type
530 def tx_for_sig(self
,i
):
531 return self
.serialize(self
.inputs
, self
.outputs
, for_sig
= i
)
535 return Hash(self
.raw
.decode('hex') )[::-1].encode('hex')
537 def add_signature(self
, i
, pubkey
, sig
):
538 txin
= self
.inputs
[i
]
539 signatures
= txin
.get("signatures",{})
540 signatures
[pubkey
] = sig
541 txin
["signatures"] = signatures
542 self
.inputs
[i
] = txin
543 print_error("adding signature for", pubkey
)
544 self
.raw
= self
.serialize( self
.inputs
, self
.outputs
)
547 def is_complete(self
):
548 for i
, txin
in enumerate(self
.inputs
):
549 redeem_script
= txin
.get('redeemScript')
550 num
, redeem_pubkeys
= parse_redeemScript(redeem_script
) if redeem_script
else (1, [txin
.get('redeemPubkey')])
551 signatures
= txin
.get("signatures",{})
552 if len(signatures
) == num
:
560 def sign(self
, keypairs
):
561 print_error("tx.sign(), keypairs:", keypairs
)
563 for i
, txin
in enumerate(self
.inputs
):
565 # if the input is multisig, parse redeem script
566 redeem_script
= txin
.get('redeemScript')
567 num
, redeem_pubkeys
= parse_redeemScript(redeem_script
) if redeem_script
else (1, [txin
.get('redeemPubkey')])
570 txin
["pubkeys"] = redeem_pubkeys
571 # get list of already existing signatures
572 signatures
= txin
.get("signatures",{})
573 # continue if this txin is complete
574 if len(signatures
) == num
:
577 for_sig
= Hash(self
.tx_for_sig(i
).decode('hex'))
578 for pubkey
in redeem_pubkeys
:
579 if pubkey
in keypairs
.keys():
581 sec
= keypairs
[pubkey
]
582 pkey
= regenerate_key(sec
)
584 private_key
= ecdsa
.SigningKey
.from_secret_exponent( secexp
, curve
= SECP256k1
)
585 public_key
= private_key
.get_verifying_key()
586 sig
= private_key
.sign_digest_deterministic( for_sig
, hashfunc
=hashlib
.sha256
, sigencode
= ecdsa
.util
.sigencode_der
)
587 assert public_key
.verify_digest( sig
, for_sig
, sigdecode
= ecdsa
.util
.sigdecode_der
)
588 self
.add_signature(i
, pubkey
, sig
.encode('hex'))
591 print_error("is_complete", self
.is_complete())
592 self
.raw
= self
.serialize( self
.inputs
, self
.outputs
)
596 def deserialize(self
):
598 vds
.write(self
.raw
.decode('hex'))
600 start
= vds
.read_cursor
601 d
['version'] = vds
.read_int32()
602 n_vin
= vds
.read_compact_size()
604 for i
in xrange(n_vin
):
605 d
['inputs'].append(self
.parse_input(vds
))
606 n_vout
= vds
.read_compact_size()
608 for i
in xrange(n_vout
):
609 d
['outputs'].append(self
.parse_output(vds
, i
))
610 d
['lockTime'] = vds
.read_uint32()
615 def parse_input(self
, vds
):
617 prevout_hash
= hash_encode(vds
.read_bytes(32))
618 prevout_n
= vds
.read_uint32()
619 scriptSig
= vds
.read_bytes(vds
.read_compact_size())
620 sequence
= vds
.read_uint32()
622 if prevout_hash
== '00'*32:
623 d
['is_coinbase'] = True
625 d
['is_coinbase'] = False
626 d
['prevout_hash'] = prevout_hash
627 d
['prevout_n'] = prevout_n
628 d
['sequence'] = sequence
634 parse_scriptSig(d
, scriptSig
)
638 def parse_output(self
, vds
, i
):
640 d
['value'] = vds
.read_int64()
641 scriptPubKey
= vds
.read_bytes(vds
.read_compact_size())
642 is_pubkey
, address
= get_address_from_output_script(scriptPubKey
)
643 d
['is_pubkey'] = is_pubkey
644 d
['address'] = address
645 d
['scriptPubKey'] = scriptPubKey
.encode('hex')
650 def add_extra_addresses(self
, txlist
):
651 for i
in self
.inputs
:
652 if i
.get("address") == "(pubkey)":
653 prev_tx
= txlist
.get(i
.get('prevout_hash'))
655 address
, value
= prev_tx
.outputs
[i
.get('prevout_n')]
656 print_error("found pay-to-pubkey address:", address
)
657 i
["address"] = address
660 def has_address(self
, addr
):
662 for txin
in self
.inputs
:
663 if addr
== txin
.get('address'):
666 for txout
in self
.outputs
:
673 def get_value(self
, addresses
, prevout_values
):
674 # return the balance for that tx
679 v_in
= v_out
= v_out_mine
= 0
681 for item
in self
.inputs
:
682 addr
= item
.get('address')
683 if addr
in addresses
:
686 key
= item
['prevout_hash'] + ':%d'%item
['prevout_n']
687 value
= prevout_values
.get( key
)
695 if not is_send
: is_partial
= False
697 for item
in self
.outputs
:
700 if addr
in addresses
:
705 # some inputs are mine:
708 v
= v_out_mine
- v_out
714 v
= v_out_mine
- v_in
717 # some inputs are mine, but not all
721 # all inputs are mine
724 return is_relevant
, is_send
, v
, fee
727 def get_input_info(self
):
728 keys
= ['prevout_hash', 'prevout_n', 'address', 'KeyID', 'scriptPubKey', 'redeemScript', 'redeemPubkey', 'pubkeys', 'signatures', 'is_coinbase']
730 for i
in self
.inputs
:
744 "complete":self
.is_complete()
747 if not self
.is_complete():
748 input_info
= self
.get_input_info()
749 out
['input_info'] = json
.dumps(input_info
).replace(' ','')
754 def requires_fee(self
, verifier
):
755 # see https://en.bitcoin.it/wiki/Transaction_fees
757 size
= len(self
.raw
)/2
761 for o
in self
.outputs
:
766 for i
in self
.inputs
:
767 age
= verifier
.get_confirmations(i
["prevout_hash"])[0]
768 sum += i
["value"] * age
769 priority
= sum / size
770 print_error(priority
, threshold
)
771 return priority
< threshold
775 def add_input_info(self
, input_info
):
776 for i
, txin
in enumerate(self
.inputs
):
778 txin
['scriptPubKey'] = item
['scriptPubKey']
779 txin
['redeemScript'] = item
.get('redeemScript')
780 txin
['redeemPubkey'] = item
.get('redeemPubkey')
781 txin
['KeyID'] = item
.get('KeyID')
782 txin
['signatures'] = item
.get('signatures',{})