Ejemplo n.º 1
0
    def import_json( self, json_text ):
        try:
            importTxInfo = json.loads( json_text )
        except:
            raise RuntimeError( "Invalid Input", "The input doesn't parse to valid json." )

        try: 
            if 'tx' not in importTxInfo:
                raise ValueError( "No transaction found in json" )

            redeemScriptCanidate = None
    
            try: 
		self.tx = bitcoin.deserialize( importTxInfo['tx'] )
                sigScript = self.tx['ins'][0]['script']
                if sigScript != "":
                    sigScript = bitcoin.deserialize_script( sigScript )
                    redeemScriptCanidate = sigScript[-1]
            except Exception as e:
                raise ValueError( "tx could not be deserialized:" + str( e ) )

            if 'input' in importTxInfo and 'redeemScript' in importTxInfo['input']:
                if redeemScriptCanidate is not None and redeemScriptCanidate.lower() != importTxInfo['input']['redeemScript'].lower():
                    raise ValueError( "redeemScript given in info doesn't match redeemScript from partial signature" )
                redeemScriptCanidate = importTxInfo['input']['redeemScript']

            if redeemScriptCanidate is not None:
                self.pubs, self.neededSigs = KeyHelper.parse_redeem_script( redeemScriptCanidate )
                self.redeemScript = redeemScriptCanidate
            else:
                raise ValueError( "No redeemScript can be located." )

        except ValueError as e:
            raise RuntimeError( "Invalid Input", str( e ) )
Ejemplo n.º 2
0
def tx_script_to_asm( script_hex ):
    """
    Decode a script into assembler
    """
    if len(script_hex) == 0:
        return ""

    try:
        script_array = bitcoin.deserialize_script( script_hex )
    except:
        log.error("Failed to convert '%s' to assembler" % script_hex)
        raise

    script_tokens = []
    for token in script_array:
        if token is None:
            token = 0

        token_name = None

        if type(token) in [int,long]:
            token_name = OPCODE_NAMES.get(token, None)
            if token_name is None:
                token_name = str(token)
        
        else:
            token_name = token

        script_tokens.append(token_name)

    return " ".join(script_tokens)
Ejemplo n.º 3
0
    def extract_sigs( self, tx ):
        sigScript = tx['ins'][0]['script']
        if sigScript == "":
            return []

        sigScript = bitcoin.deserialize_script( sigScript )
        return sigScript[1:-1]
Ejemplo n.º 4
0
	def add_signature(self, nick, sigb64):
		if nick not in self.nonrespondants:
			debug('add_signature => nick=' + nick + ' not in nonrespondants ' + str(self.nonrespondants))
			return
		sig = base64.b64decode(sigb64).encode('hex')
		inserted_sig = False
		txhex = btc.serialize(self.latest_tx)
		
		#batch retrieval of utxo data
		utxo = {}
		ctr = 0
		for index, ins in enumerate(self.latest_tx['ins']):
			utxo_for_checking = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
			if ins['script'] != '' or  utxo_for_checking in self.input_utxos.keys():
				continue
			utxo[ctr] = [index, utxo_for_checking]
			ctr += 1
		utxo_data = common.bc_interface.query_utxo_set([x[1] for x in utxo.values()])
		#insert signatures
		for i,u in utxo.iteritems():
			if utxo_data[i] == None:
				continue
			sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'], *btc.deserialize_script(sig))
			if sig_good:
				debug('found good sig at index=%d' % (u[0]))
				self.latest_tx['ins'][u[0]]['script'] = sig
				inserted_sig = True
				#check if maker has sent everything possible
				self.utxos[nick].remove(u[1])
				if len(self.utxos[nick]) == 0:
					debug('nick = ' + nick + ' sent all sigs, removing from nonrespondant list')
					self.nonrespondants.remove(nick)
				break
		if not inserted_sig:
			debug('signature did not match anything in the tx')
			#TODO what if the signature doesnt match anything
			# nothing really to do except drop it, carry on and wonder why the
			# other guy sent a failed signature

		tx_signed = True
		for ins in self.latest_tx['ins']:
			if ins['script'] == '':
				tx_signed = False
		if not tx_signed:
			return
		self.end_timeout_thread = True
		self.all_responded = True
		with self.timeout_lock:
			self.timeout_lock.notify()
		debug('all makers have sent their signatures')
		for index, ins in enumerate(self.latest_tx['ins']):
			#remove placeholders
			if ins['script'] == 'deadbeef':
				ins['script'] = ''
		if self.finishcallback != None:
			self.finishcallback(self)
Ejemplo n.º 5
0
 def decode(cls, vout, n, network):
     hex_script = vout['script']
     script = [0 if x == None else x for x in deserialize_script(hex_script)]
     data = {'hs': hex_script,
             'd': vout,
             'n': n,
             's': script,
             'p': {'pub': 0x00 if network == "main" else 0x6F,
                   'p2sh': 0x05 if network == "main" else 0xC4}}
     return VOUTDecoder.__decode(data)
Ejemplo n.º 6
0
    def parse_redeem_script( script ):
        try:
            elements = bitcoin.deserialize_script( script )
            if elements[-1] != 174:
                raise ValueError( "no OP_CHECKMULTISIG found in redeemScript" )

            if elements[-2] < elements[0]:
                raise ValueError( "redeemscript asks for more sigs than supplies keys" )

            return elements[1:(1+elements[-2])], elements[0]
        except Exception as e:
            raise ValueError( "redeemScript not in valid format: " + str(e) )
Ejemplo n.º 7
0
    def dataReceived(self, data):
        m = deserialize(data)

        if m["message"]["command"] == "verack":
            """Complete the handshake if we received both version and verack"""
            self.timeouts["verack"].cancel()
            del self.timeouts["verack"]
            if "version" not in self.timeouts:
                self.on_handshake_complete()

        elif m["message"]["command"] == "version":
            """Send the verack back"""
            # TODO: make sure this node uses NODE_NETWORK (and maybe NODE_BLOOM in the future)
            self.timeouts["version"].cancel()
            del self.timeouts["version"]
            self.transport.write(serialize(message(verack(), self.params)))
            if "verack" not in self.timeouts:
                self.on_handshake_complete()

        elif m["message"]["command"] == "inv":
            """Run through our callbacks to see if we are waiting on any of these inventory items"""
            inventory = deserialize(m["message"]["payload"], "inv")
            for item in inventory["inv"]:
                if item[1] in self.callbacks:
                    self.callbacks[item[1]](item[1])
                    del self.callbacks[item[1]]
                elif item[0] == "TX":
                    self.send_message(message(get_data(item[0], item[1]), self.params))
                print "Peer %s:%s announced new %s %s" % (self.transport.getPeer().host, self.transport.getPeer().port, item[0], item[1])

        elif m["message"]["command"] == "getdata":
            """Serve the data from inventory if we have it"""
            data_request = deserialize(m["message"]["payload"], "getdata")
            for item in data_request["getdata"]:
                if item[1] in self.inventory and item[0] == "TX":
                    transaction = tx(self.inventory[item[1]])
                    self.send_message(message(transaction, self.params))

        elif m["message"]["command"] == "tx":
            """Parse to check the script_pubkey data element against our subscriptions"""
            t = deserialize(m["message"]["payload"], "tx")
            for out in t['tx']['outs']:
                script = bitcoin.deserialize_script(out['script'])
                data_element = script[2] if len(script) == 5 else script[1]
                if data_element in self.callbacks:
                    self.callbacks[data_element](t)

        else:
            print "Received message %s from %s:%s" % (m["message"]["command"], self.transport.getPeer().host, self.transport.getPeer().port)
Ejemplo n.º 8
0
	def add_signature(self, sigb64):
		sig = base64.b64decode(sigb64).encode('hex')
		inserted_sig = False
		txhex = btc.serialize(self.latest_tx)
		
		#batch retrieval of utxo data
		utxo = {}
		ctr = 0
		for index, ins in enumerate(self.latest_tx['ins']):
			utxo_for_checking = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
			if ins['script'] != '' or  utxo_for_checking in self.input_utxos.keys():
				continue
			utxo[ctr] = [index, utxo_for_checking]
			ctr += 1
		utxo_data = common.bc_interface.query_utxo_set([x[1] for x in utxo.values()])
		#insert signatures
		for i,u in utxo.iteritems():
			if utxo_data[i] == None:
				continue
			sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'], *btc.deserialize_script(sig))
			if sig_good:
				debug('found good sig at index=%d' % (u[0]))
				self.latest_tx['ins'][u[0]]['script'] = sig
				inserted_sig = True
				break
		if not inserted_sig:
			debug('signature did not match anything in the tx')
			#TODO what if the signature doesnt match anything
			# nothing really to do except drop it, carry on and wonder why the
			# other guy sent a failed signature

		tx_signed = True
		for ins in self.latest_tx['ins']:
			if ins['script'] == '':
				tx_signed = False
		if not tx_signed:
			return
		debug('the entire tx is signed, ready to pushtx()')
		txhex = btc.serialize(self.latest_tx)
		debug('\n' + txhex)

		#TODO send to a random maker or push myself
		#self.msgchan.push_tx(self.active_orders.keys()[0], txhex)	
		self.txid = common.bc_interface.pushtx(txhex)
		debug('pushed tx ' + str(self.txid))
		if self.txid == None:
			debug('unable to pushtx')
		if self.finishcallback != None:
			self.finishcallback(self)
Ejemplo n.º 9
0
def segwit_strip_script_separator(script, index=0):
    if index == None:
        return script
    OP_CODESEPARATOR = 171
    def get_pos(script, index):
        i = 0
        for x in range(0, index):
            try:
                i = script.index(OP_CODESEPARATOR, i)
            except ValueError:
                return i
        return i + 1
    deserialized_script = deserialize_script(str(script))
    pos = get_pos(deserialized_script, index)
    return serialize_script(deserialized_script[pos:])
Ejemplo n.º 10
0
def parse_multisig_scriptsig( scriptsig_hex ):
    """
    Given a scriptsig (as hex), extract the signatures.
    Return list of signatures on success
    Return None on error
    """
    try:
        script_parts = bitcoin.deserialize_script( scriptsig_hex )
    except:
        if os.environ.get("BLOCKSTACK_TEST") == "1":
            traceback.print_exc()

        return None

    # sanity check 
    return script_parts
Ejemplo n.º 11
0
def tx_output_parse_scriptPubKey( scriptpubkey ):
    """
    Given the hex representation of a scriptPubKey,
    turn it into a nice, easy-to-read dict like what
    bitcoind would give us.
    """
    script_tokens = bitcoin.deserialize_script( scriptpubkey )
    script_type = None
    reqSigs = None
    addresses = []
    if scriptpubkey.startswith("76a914") and scriptpubkey.endswith("88ac") and len(scriptpubkey) == 50:
        script_type = "pubkeyhash"
        reqSigs = 1
        addresses = [ script_hex_to_address(scriptpubkey) ]

    elif scriptpubkey.startswith("a914") and scriptpubkey.endswith("87") and len(scriptpubkey) == 46:
        script_type = "scripthash"
        reqsigs = 1
        addresses = [ script_hex_to_address(scriptpubkey) ]

    elif script_tokens[-1] == OPCODE_VALUES["OP_CHECKMULTISIG"]:
        script_type = "multisig"

    elif script_tokens[0] == OPCODE_VALUES["OP_RETURN"] and len(script_tokens) == 2:
        script_type = "nulldata"

    elif len(script_tokens) == 2 and script_tokens[-1] == OPCODE_VALUES["OP_CHECKSIG"]:
        script_type = "pubkey"
        reqSigs = 1

    else:
        script_type = "nonstandard"

    ret = {
        "asm": tx_script_to_asm(scriptpubkey),
        "hex": scriptpubkey,
        "type": script_type
    }

    if addresses is not None:
        ret['addresses'] = addresses

    if reqSigs is not None:
        ret['reqSigs'] = reqSigs

    return ret
Ejemplo n.º 12
0
def parse_multisig_redeemscript( redeem_script_hex ):
    """
    Given a redeem script (as hex), extract multisig information.
    Return m, list of public keys on success
    Return (None, None)
    """
    script_parts = []
    redeem_script_hex = str(redeem_script_hex)

    try:
        script_parts = bitcoin.deserialize_script( redeem_script_hex )
    except:
        if os.environ.get("BLOCKSTACK_TEST") == "1":
            traceback.print_exc()
            print >> sys.stderr, "Invalid redeem script %s" % redeem_script_hex

        return None, None

    try:
        assert len(script_parts) > 2
        assert script_parts[-1] == opcodes.OP_CHECKMULTISIG
        script_parts.pop(-1)

        # get n
        n = script_parts.pop(-1)
        pubkeys = []

        # get m
        m = script_parts.pop(0)

        for i in xrange(0, n):
            pubk = script_parts.pop(0)
            
            # must be a public key
            BitcoinPublicKey(pubk)
            pubkeys.append(pubk)

        assert len(script_parts) == 0, "script_parts = %s" % script_parts
        return (m, pubkeys)
    except Exception, e:
        if os.environ.get("BLOCKSTACK_TEST") == "1":
            traceback.print_exc()
            print >> sys.stderr, "Invalid redeem script %s (parses to %s)" % (redeem_script_hex, script_parts)

        return (None, None)
Ejemplo n.º 13
0
def decode_multisig_script(script):
    scriptSig = bitcoin.deserialize_script(script)
    redeemScript = hexlify(scriptSig[-1])
    (M, N, pubkeys) = decode_redeem_script(redeemScript)
    sigs = []
    for sig in scriptSig[1:-1]:
        sigs.append(hexlify(sig))
    return (sigs, pubkeys, redeemScript, M, N)
    
    
    
    
    
    

    
    

    
Ejemplo n.º 14
0
	def add_signature(self, sigb64):
		sig = base64.b64decode(sigb64).encode('hex')
		inserted_sig = False
		tx = btc.serialize(self.latest_tx)
		for index, ins in enumerate(self.latest_tx['ins']):
			if ins['script'] != '':
				continue
			utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
			utxo_data = common.bc_interface.query_utxo_set(utxo)
			if utxo_data[0] == None:
				continue
			sig_good = btc.verify_tx_input(tx, index, utxo_data[0]['script'], *btc.deserialize_script(sig))
			if sig_good:
				debug('found good sig at index=%d' % (index))
				ins['script'] = sig
				inserted_sig = True
				break
		if not inserted_sig:
			debug('signature did not match anything in the tx')
			#TODO what if the signature doesnt match anything
			# nothing really to do except drop it, carry on and wonder why the
			# other guy sent a failed signature

		tx_signed = True
		for ins in self.latest_tx['ins']:
			if ins['script'] == '':
				tx_signed = False
		if not tx_signed:
			return
		debug('the entire tx is signed, ready to pushtx()')
		txhex = btc.serialize(self.latest_tx)
		debug('\n' + txhex)

		#TODO send to a random maker or push myself
		#self.msgchan.push_tx(self.active_orders.keys()[0], txhex)	
		txid = common.bc_interface.pushtx(txhex)
		debug('pushed tx ' + str(txid))
		if self.finishcallback != None:
			self.finishcallback(self)
Ejemplo n.º 15
0
 def _decode_script(cls, vin):
     ds = [0 if x == None else x for x in deserialize_script(vin['script'])]
     asm = ''
     for i, x in enumerate(ds):
         try:
             y = int(x, 16) if isinstance(x, str) else x
             if 256 > y > 128 and y not in range(139, 176):
                 asm += '{}'.format(128 - y)
             else:
                 asm += '{}'.format(SCRIPTS[y] if len(ds) > 1 else int().from_bytes(binascii.unhexlify(y),
                                                                                    byteorder='little'))
         except:
             to_int = int().from_bytes(binascii.unhexlify(x), byteorder="little")
             # FIXME - Sometimes bytes wrap into hex, sometimes into dec
             asm += str(to_int if to_int < 1418797546 else x)
         if i < len(ds)-1:
             asm += ' '
     return {'txid': vin['outpoint']['hash'],
             'vout': vin['outpoint']['index'],
             'scriptSig': {'hex': vin['script'],
                           'asm': asm
                           },
             'sequence': vin['sequence']}
Ejemplo n.º 16
0
def test_donation_address(setup_donations, amount):
    wallets = make_wallets(1, wallet_structures=[[1,1,1,0,0]],
                               mean_amt=0.5)
    wallet = wallets[0]['wallet']
    jm_single().bc_interface.sync_wallet(wallet)
    #make a rdp from a simple privkey
    rdp_priv = "\x01"*32
    reusable_donation_pubkey = binascii.hexlify(secp256k1.PrivateKey(
        privkey=rdp_priv, raw=True, ctx=btc.ctx).pubkey.serialize())    
    dest_addr, sign_k = donation_address(reusable_donation_pubkey)
    print dest_addr
    jm_single().bc_interface.rpc('importaddress',
                                [dest_addr, '', False])    
    ins_full = wallet.unspent
    total = sum(x['value'] for x in ins_full.values())
    ins = ins_full.keys()
    output_addr = wallet.get_new_addr(1, 1)
    fee_est = 10000
    outs = [{'value': amount,
             'address': dest_addr}, {'value': total - amount - fee_est,
                                       'address': output_addr}]

    tx = btc.mktx(ins, outs)
    de_tx = btc.deserialize(tx)
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        addr = ins_full[utxo]['address']
        priv = wallet.get_key_from_addr(addr)
        priv = binascii.unhexlify(priv)
        usenonce = binascii.unhexlify(sign_k) if index == 0 else None
        if index == 0:
            log.debug("Applying rdp to input: " + str(ins))
        tx = btc.sign(tx, index, priv, usenonce=usenonce)
    #pushtx returns False on any error
    push_succeed = jm_single().bc_interface.pushtx(tx)
    if push_succeed:
        log.debug(btc.txhash(tx))
    else:
        assert False
    #Role of receiver: regenerate the destination private key,
    #and address, from the nonce of the first input; check it has
    #received the coins.
    detx = btc.deserialize(tx)
    first_utxo_script = detx['ins'][0]['script']
    sig, pub = btc.deserialize_script(first_utxo_script)
    log.debug(sig)
    sig = binascii.unhexlify(sig)
    kGlen = ord(sig[3])
    kG = sig[4:4+kGlen]
    log.debug(binascii.hexlify(kG))
    if kG[0] == "\x00":
        kG = kG[1:]
    #H(rdp private key * K) + rdp should be ==> dest addr
    #Open issue: re-introduce recovery without ECC shenanigans
    #Just cheat by trying both signs for pubkey
    coerced_kG_1 = "02" + binascii.hexlify(kG)
    coerced_kG_2 = "03" + binascii.hexlify(kG)
    for coerc in [coerced_kG_1, coerced_kG_2]:
        c = btc.sha256(btc.multiply(binascii.hexlify(rdp_priv), coerc, True))
        pub_check = btc.add_pubkeys([reusable_donation_pubkey,
                                     btc.privtopub(c+'01', True)], True)
        addr_check = btc.pubtoaddr(pub_check, get_p2pk_vbyte())
        log.debug("Found checked address: " + addr_check)
        if addr_check == dest_addr:
            time.sleep(3)
            received = jm_single().bc_interface.get_received_by_addr(
                    [dest_addr], None)['data'][0]['balance']
            assert received == amount
            return
    assert False
Ejemplo n.º 17
0
    def handle_block( self, message_header, block ):
        """
        Got a block.
        * validate it
        * load its transactions
        * ask for each transaction's sender transaction
        """

        if self.have_all_block_data():
            self.loop_exit()
            return

        block_hash = block.calculate_hash()
        
        # is this a solicited block?
        if block_hash not in self.block_info.keys():
            log.error("Ignoring unsolicited block %s" % block_hash)
            return
        
        header = self.block_info[block_hash]['header']
        height = self.block_info[block_hash]['height']
        
        log.debug("handle block %s (%s)" % (height, block_hash))

        # does this block's transaction hashes match the merkle root?
        tx_hashes = [block.txns[i].calculate_hash() for i in xrange(0, len(block.txns))]
        mr = pybitcoin.MerkleTree( tx_hashes ).root()

        if mr != header['merkle_root']:
            log.error("Merkle root of %s (%s) mismatch: expected %s, got %s" % (block_hash, height, header['merkle_root'], mr))
            return
 
        nulldata_txs = []
        relindex = 0
        for txindex in xrange(0, len(block.txns)):

            txdata = self.parse_tx( block.txns[txindex], header, block_hash, txindex )

            # if there is no nulldata output, then we don't care about this one.
            has_nulldata = False
            nulldata_payload = None
            for outp in txdata['vout']:
                if outp['scriptPubKey']['type'] == 'nulldata':
                    has_nulldata = True
                    nulldata_payload = bitcoin.deserialize_script(outp['scriptPubKey']['hex'])[1]
                    if type(nulldata_payload) not in [str, unicode]:
                        # this is a malformed OP_RETURN, where the varint that should follow OP_RETURN doesn't have the data behind it.
                        # just take the data after the varint, no matter what it is (i.e. "6a52" will be "")
                        nulldata_payload = outp['scriptPubKey']['hex'][4:]

            # count all txs processed
            self.num_txs_processed += 1

            if not has_nulldata:
                continue

            # remember nulldata
            txdata['nulldata'] = nulldata_payload 
            
            # calculate total output (part of fee; will be debited when we discover the senders)
            txdata['fee'] -= sum( int(out['value'] * 10**8) for out in txdata['vout'] )

            # remember the relative tx index (i.e. the ith nulldata tx)
            txdata['relindex'] = relindex
            
	    # do we actually want this?
            if self.tx_filter is not None:
                if not self.tx_filter( txdata ):
                    continue

            # yup, we want it!
            relindex += 1
            nulldata_txs.append( txdata )


        self.block_info[block_hash]['txns'] = nulldata_txs
        self.block_info[block_hash]['num_txns'] = len(block.txns)
        self.block_info[block_hash]['num_senders'] = 0

        # get each input's transaction
        sender_txhashes = []

        for txn in self.block_info[block_hash]['txns']:
            for i in xrange(0, len(txn['vin'])):

                # record information about the transaction
                # that created this input (so we can go find
                # it later).
                inp = txn['vin'][i]
                sender_txid = inp['txid']
                inp_sender_outp = inp['vout']

                if str(sender_txid) not in sender_txhashes:
                    sender_txhashes.append( str(sender_txid) )

                sinfo = self.make_sender_info( block_hash, txn, i )

                if not self.sender_info.has_key(sender_txid):
                    # map outpoint for this input to the tx info
                    self.sender_info[sender_txid] = {}

                # sinfo is the information from the output in 
                # the sender-tx that funded inp
                self.sender_info[sender_txid][inp_sender_outp] = sinfo


        # update accounting...
        self.num_blocks_received += 1
        self.block_info[block_hash]['handled'] = True

        log.debug("Request %s nulldata sender TXs" % len(sender_txhashes))

        if self.have_all_block_data():
            self.loop_exit()

        return
Ejemplo n.º 18
0
    def handle_block( self, message_header, block ):
        """
        Got a block.
        * validate it
        * load its transactions
        * ask for each transaction's sender transaction
        """

        if self.have_all_block_data():
            self.loop_exit()
            return

        block_hash = block.calculate_hash()
        
        # is this a solicited block?
        if block_hash not in self.block_info.keys():
            log.error("Ignoring unsolicited block %s" % block_hash)
            return
        
        header = self.block_info[block_hash]['header']
        height = self.block_info[block_hash]['height']
        
        log.debug("handle block %s (%s)" % (height, block_hash))

        # does this block's transaction hashes match the merkle root?
        tx_hashes = [block.txns[i].calculate_hash() for i in xrange(0, len(block.txns))]
        mr = pybitcoin.MerkleTree( tx_hashes ).root()

        if mr != header['merkle_root']:
            log.error("Merkle root of %s (%s) mismatch: expected %s, got %s" % (block_hash, height, header['merkle_root'], mr))
            return
 
        nulldata_txs = []
        relindex = 0
        for txindex in xrange(0, len(block.txns)):

            txdata = self.parse_tx( block.txns[txindex], header, block_hash, txindex )

            # if there is no nulldata output, then we don't care about this one.
            has_nulldata = False
            nulldata_payload = None
            for outp in txdata['vout']:
                if outp['scriptPubKey']['type'] == 'nulldata':
                    has_nulldata = True
                    nulldata_payload = bitcoin.deserialize_script(outp['scriptPubKey']['hex'])[1]
                    if type(nulldata_payload) not in [str, unicode]:
                        # this is a malformed OP_RETURN, where the varint that should follow OP_RETURN doesn't have the data behind it.
                        # just take the data after the varint, no matter what it is (i.e. "6a52" will be "")
                        nulldata_payload = outp['scriptPubKey']['hex'][4:]

            # count all txs processed
            self.num_txs_processed += 1

            if not has_nulldata:
                continue

            # remember nulldata
            txdata['nulldata'] = nulldata_payload 
            
            # calculate total output (part of fee; will be debited when we discover the senders)
            txdata['fee'] -= sum( int(out['value'] * 10**8) for out in txdata['vout'] )

            # remember the relative tx index (i.e. the ith nulldata tx)
            txdata['relindex'] = relindex
            
	    # do we actually want this?
            if self.tx_filter is not None:
                if not self.tx_filter( txdata ):
                    continue

            # yup, we want it!
            relindex += 1
            nulldata_txs.append( txdata )


        self.block_info[block_hash]['txns'] = nulldata_txs
        self.block_info[block_hash]['num_txns'] = len(block.txns)
        self.block_info[block_hash]['num_senders'] = 0

        # get each input's transaction
        sender_txhashes = []

        for txn in self.block_info[block_hash]['txns']:
            for i in xrange(0, len(txn['vin'])):

                # record information about the transaction
                # that created this input (so we can go find
                # it later).
                inp = txn['vin'][i]
                sender_txid = inp['txid']
                inp_sender_outp = inp['vout']

                if str(sender_txid) not in sender_txhashes:
                    sender_txhashes.append( str(sender_txid) )

                sinfo = self.make_sender_info( block_hash, txn, i )

                if not self.sender_info.has_key(sender_txid):
                    # map outpoint for this input to the tx info
                    self.sender_info[sender_txid] = {}

                # sinfo is the information from the output in 
                # the sender-tx that funded inp
                self.sender_info[sender_txid][inp_sender_outp] = sinfo


        # update accounting...
        self.num_blocks_received += 1
        self.block_info[block_hash]['handled'] = True

        log.debug("Request %s nulldata sender TXs" % len(sender_txhashes))

        if self.have_all_block_data():
            self.loop_exit()

        return
Ejemplo n.º 19
0
    def add_signature(self, nick, sigb64):
        if nick not in self.nonrespondants:
            log.debug(
                ('add_signature => nick={} '
                 'not in nonrespondants {}').format(nick, self.nonrespondants))
            return
        sig = base64.b64decode(sigb64).encode('hex')
        inserted_sig = False
        txhex = btc.serialize(self.latest_tx)

        # batch retrieval of utxo data
        utxo = {}
        ctr = 0
        for index, ins in enumerate(self.latest_tx['ins']):
            utxo_for_checking = ins['outpoint']['hash'] + ':' + str(
                ins['outpoint']['index'])
            if (ins['script'] != ''
                    or utxo_for_checking in self.input_utxos.keys()):
                continue
            utxo[ctr] = [index, utxo_for_checking]
            ctr += 1
        utxo_data = jm_single().bc_interface.query_utxo_set(
            [x[1] for x in utxo.values()])

        # insert signatures
        for i, u in utxo.iteritems():
            if utxo_data[i] is None:
                continue
            sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'],
                                           *btc.deserialize_script(sig))
            if sig_good:
                log.debug('found good sig at index=%d' % (u[0]))
                self.latest_tx['ins'][u[0]]['script'] = sig
                inserted_sig = True
                # check if maker has sent everything possible
                self.utxos[nick].remove(u[1])
                if len(self.utxos[nick]) == 0:
                    log.info(('nick = {} sent all sigs, removing from '
                              'nonrespondant list').format(nick))
                    self.nonrespondants.remove(nick)
                break
        if not inserted_sig:
            log.debug('signature did not match anything in the tx')
            # TODO what if the signature doesnt match anything
            # nothing really to do except drop it, carry on and wonder why the
            # other guy sent a failed signature

        tx_signed = True
        for ins in self.latest_tx['ins']:
            if ins['script'] == '':
                tx_signed = False
        if not tx_signed:
            return
        self.end_timeout_thread = True
        self.all_responded = True
        with self.timeout_lock:
            self.timeout_lock.notify()
        log.info('all makers have sent their signatures')
        for index, ins in enumerate(self.latest_tx['ins']):
            # remove placeholders
            if ins['script'] == 'deadbeef':
                ins['script'] = ''
        if self.finishcallback is not None:
            self.finishcallback(self)