move transaction code and fix issue #280
[electrum-nvc.git] / lib / bitcoin.py
index c4e111b..792aa3b 100644 (file)
@@ -460,300 +460,6 @@ def bip32_private_key(sequence, k, chain):
 
 MIN_RELAY_TX_FEE = 10000
 
-class Transaction:
-    
-    def __init__(self, raw):
-        self.raw = raw
-        self.deserialize()
-        self.inputs = self.d['inputs']
-        self.outputs = self.d['outputs']
-        self.outputs = map(lambda x: (x['address'],x['value']), self.outputs)
-        self.input_info = None
-        self.is_complete = True
-        
-    @classmethod
-    def from_io(klass, inputs, outputs):
-        raw = klass.serialize(inputs, outputs, for_sig = -1) # for_sig=-1 means do not sign
-        self = klass(raw)
-        self.is_complete = False
-        self.inputs = inputs
-        self.outputs = outputs
-        extras = []
-        for i in self.inputs:
-            e = { 'txid':i['tx_hash'], 'vout':i['index'], 'scriptPubKey':i.get('raw_output_script') }
-            extras.append(e)
-        self.input_info = extras
-        return self
-
-    def __str__(self):
-        return self.raw
-
-    @classmethod
-    def multisig_script(klass, public_keys, num=None):
-        n = len(public_keys)
-        if num is None: num = n
-        # supports only "2 of 2", and "2 of 3" transactions
-        assert num <= n and n in [2,3]
-    
-        if num==2:
-            s = '52'
-        elif num == 3:
-            s = '53'
-        else:
-            raise
-    
-        for k in public_keys:
-            s += var_int(len(k)/2)
-            s += k
-        if n==2:
-            s += '52'
-        elif n==3:
-            s += '53'
-        else:
-            raise
-        s += 'ae'
-
-        return s
-
-    @classmethod
-    def serialize( klass, inputs, outputs, for_sig = None ):
-
-        s  = int_to_hex(1,4)                                         # version
-        s += var_int( len(inputs) )                                  # number of inputs
-        for i in range(len(inputs)):
-            txin = inputs[i]
-            s += txin['tx_hash'].decode('hex')[::-1].encode('hex')   # prev hash
-            s += int_to_hex(txin['index'],4)                         # prev index
-
-            if for_sig is None:
-                signatures = txin['signatures']
-                pubkeys = txin['pubkeys']
-                if not txin.get('redeemScript'):
-                    pubkey = pubkeys[0]
-                    sig = signatures[0]
-                    sig = sig + '01'                                 # hashtype
-                    script  = op_push(len(sig)/2)
-                    script += sig
-                    script += op_push(len(pubkey)/2)
-                    script += pubkey
-                else:
-                    script = '00'                                    # op_0
-                    for sig in signatures:
-                        sig = sig + '01'
-                        script += op_push(len(sig)/2)
-                        script += sig
-
-                    redeem_script = klass.multisig_script(pubkeys,2)
-                    script += op_push(len(redeem_script)/2)
-                    script += redeem_script
-
-            elif for_sig==i:
-                if txin.get('redeemScript'):
-                    script = txin['redeemScript']                    # p2sh uses the inner script
-                else:
-                    script = txin['raw_output_script']               # scriptsig
-            else:
-                script=''
-            s += var_int( len(script)/2 )                            # script length
-            s += script
-            s += "ffffffff"                                          # sequence
-
-        s += var_int( len(outputs) )                                 # number of outputs
-        for output in outputs:
-            addr, amount = output
-            s += int_to_hex( amount, 8)                              # amount
-            addrtype, hash_160 = bc_address_to_hash_160(addr)
-            if addrtype == 0:
-                script = '76a9'                                      # op_dup, op_hash_160
-                script += '14'                                       # push 0x14 bytes
-                script += hash_160.encode('hex')
-                script += '88ac'                                     # op_equalverify, op_checksig
-            elif addrtype == 5:
-                script = 'a9'                                        # op_hash_160
-                script += '14'                                       # push 0x14 bytes
-                script += hash_160.encode('hex')
-                script += '87'                                       # op_equal
-            else:
-                raise
-            
-            s += var_int( len(script)/2 )                           #  script length
-            s += script                                             #  script
-        s += int_to_hex(0,4)                                        #  lock time
-        if for_sig is not None and for_sig != -1:
-            s += int_to_hex(1, 4)                                   #  hash type
-        return s
-
-
-    def for_sig(self,i):
-        return self.serialize(self.inputs, self.outputs, for_sig = i)
-
-
-    def hash(self):
-        return Hash(self.raw.decode('hex') )[::-1].encode('hex')
-
-
-
-    def sign(self, keypairs):
-        import deserialize
-        is_complete = True
-        print_error("tx.sign(), keypairs:", keypairs)
-
-        for i, txin in enumerate(self.inputs):
-
-            # if the input is multisig, parse redeem script
-            redeem_script = txin.get('redeemScript')
-            num, redeem_pubkeys = deserialize.parse_redeemScript(redeem_script) if redeem_script else (1, [txin.get('redeemPubkey')])
-
-            # add pubkeys
-            txin["pubkeys"] = redeem_pubkeys
-            # get list of already existing signatures
-            signatures = txin.get("signatures",[])
-            # continue if this txin is complete
-            if len(signatures) == num:
-                continue
-
-            tx_for_sig = self.serialize( self.inputs, self.outputs, for_sig = i )
-            for pubkey in redeem_pubkeys:
-                # check if we have the corresponding private key
-                if pubkey in keypairs.keys():
-                    # add signature
-                    sec = keypairs[pubkey]
-                    compressed = is_compressed(sec)
-                    pkey = regenerate_key(sec)
-                    secexp = pkey.secret
-                    private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
-                    public_key = private_key.get_verifying_key()
-                    sig = private_key.sign_digest( Hash( tx_for_sig.decode('hex') ), sigencode = ecdsa.util.sigencode_der )
-                    assert public_key.verify_digest( sig, Hash( tx_for_sig.decode('hex') ), sigdecode = ecdsa.util.sigdecode_der)
-                    signatures.append( sig.encode('hex') )
-                    print_error("adding signature for", pubkey)
-            
-            txin["signatures"] = signatures
-            is_complete = is_complete and len(signatures) == num
-
-        self.is_complete = is_complete
-        self.raw = self.serialize( self.inputs, self.outputs )
-
-
-    def deserialize(self):
-        import deserialize
-        vds = deserialize.BCDataStream()
-        vds.write(self.raw.decode('hex'))
-        self.d = deserialize.parse_Transaction(vds)
-        return self.d
-    
-
-    def has_address(self, addr):
-        found = False
-        for txin in self.inputs:
-            if addr == txin.get('address'): 
-                found = True
-                break
-        for txout in self.outputs:
-            if addr == txout[0]:
-                found = True
-                break
-        return found
-
-
-    def get_value(self, addresses, prevout_values):
-        # return the balance for that tx
-        is_relevant = False
-        is_send = False
-        is_pruned = False
-        is_partial = False
-        v_in = v_out = v_out_mine = 0
-
-        for item in self.inputs:
-            addr = item.get('address')
-            if addr in addresses:
-                is_send = True
-                is_relevant = True
-                key = item['prevout_hash']  + ':%d'%item['prevout_n']
-                value = prevout_values.get( key )
-                if value is None:
-                    is_pruned = True
-                else:
-                    v_in += value
-            else:
-                is_partial = True
-
-        if not is_send: is_partial = False
-                    
-        for item in self.outputs:
-            addr, value = item
-            v_out += value
-            if addr in addresses:
-                v_out_mine += value
-                is_relevant = True
-
-        if is_pruned:
-            # some inputs are mine:
-            fee = None
-            if is_send:
-                v = v_out_mine - v_out
-            else:
-                # no input is mine
-                v = v_out_mine
-
-        else:
-            v = v_out_mine - v_in
-
-            if is_partial:
-                # some inputs are mine, but not all
-                fee = None
-                is_send = v < 0
-            else:
-                # all inputs are mine
-                fee = v_out - v_in
-
-        return is_relevant, is_send, v, fee
-
-    def as_dict(self):
-        import json
-        out = {
-            "hex":self.raw,
-            "complete":self.is_complete
-            }
-        if not self.is_complete:
-            extras = []
-            for i in self.inputs:
-                e = { 'txid':i['tx_hash'], 'vout':i['index'],
-                      'scriptPubKey':i.get('raw_output_script'),
-                      'KeyID':i.get('KeyID'),
-                      'redeemScript':i.get('redeemScript'),
-                      'signatures':i.get('signatures'),
-                      'pubkeys':i.get('pubkeys'),
-                      }
-                extras.append(e)
-            self.input_info = extras
-
-            if self.input_info:
-                out['input_info'] = json.dumps(self.input_info).replace(' ','')
-
-        return out
-
-
-    def requires_fee(self, verifier):
-        # see https://en.bitcoin.it/wiki/Transaction_fees
-        threshold = 57600000
-        size = len(self.raw)/2
-        if size >= 10000: 
-            return True
-
-        for o in self.outputs:
-            value = o[1]
-            if value < 1000000:
-                return True
-        sum = 0
-        for i in self.inputs:
-            age = verifier.get_confirmations(i["tx_hash"])[0]
-            sum += i["value"] * age
-        priority = sum / size
-        print_error(priority, threshold)
-        return priority < threshold 
-
-
 
 
 def test_bip32(seed, sequence):