s = settings.Settings("../amikopay.conf") d = bitcoind.Bitcoind(s) #(these addresses are mine - thanks for donating :-P) keyHash1 = binascii.unhexlify("fd5627c5eff58991dec54877272e82f758ea8b65") keyHash2 = binascii.unhexlify("ab22c699d3e72f2c1e4896508bf9d8d7910104d0") address1 = base58.encodeBase58Check(keyHash1, 0) address2 = base58.encodeBase58Check(keyHash2, 0) print address1 print address2 #Note: this will fail, unless you change toe above addresses to some of your own privKey1 = base58.decodeBase58Check(d.getPrivateKey(address1), 128) privKey2 = base58.decodeBase58Check(d.getPrivateKey(address2), 128) key1 = Key() key1.setPrivateKey(privKey1) key2 = Key() key2.setPrivateKey(privKey2) print key1.getPublicKey().encode("hex") print key2.getPublicKey().encode("hex") amount = int(100000 * float(raw_input("Amount to be transferred (mBTC): "))) fee = 10000 #0.1 mBTC outputHash = binascii.unhexlify(raw_input("Input hash (empty: create multisig): "))[::-1]
def getInputsForAmount(bitcoind, amount): """ Returns information about unspent outputs, which are available to be used as inputs for a new transaction, and have a total amount that is at least the requested amount. Arguments: bitcoind: Bitcoind; the bitcoin daemon from which to retrieve this information amount: int; the minimum total amount (in Satoshi) Return value: tuple (total, inputs) total: int; the actual total amount (in Satoshi); total >= amount inputs: list of tuple (txid, vout, scriptPubKey, privateKey); the input information txid: str; input transaction ID. Note that the byte order is the reverse as shown in Bitcoin. vout: int; input transaction index scriptPubKey: str; input transaction scriptPubKey (serialized) privateKey: str; corresponding private key Exceptions: Exception: insufficient funds """ unspent = bitcoind.listUnspent() #Filter: only use "normal" outputs, not multisig etc. unspent = [u for u in unspent if "address" in u] #TODO: think about the best policy here. #Possible objectives: # - minimizing taint between addresses (privacy protection) # - minimizing coin fragmentation (transaction size, related to fee costs) # - choosing old coins (related to fee costs) #For now, an attempt is made to minimize coin fragmentation. unspent.sort(cmp=lambda a, b: cmp(a["amount"], b["amount"])) used = None total = 0 for u in unspent: if u["amount"] >= amount: used = [u] total = u["amount"] break if used is None: used = [] while total < amount: try: u = unspent.pop() except IndexError: raise Exception("Insufficient funds") used.append(u) total += u["amount"] for u in used: address = u["address"] u["privateKey"] = base58.decodeBase58Check( bitcoind.getPrivateKey(address), 128) return total, [(u["txid"], u["vout"], u["scriptPubKey"], u["privateKey"]) for u in used]
def getInputsForAmount(bitcoind, amount): """ Returns information about unspent outputs, which are available to be used as inputs for a new transaction, and have a total amount that is at least the requested amount. Arguments: bitcoind: Bitcoind; the bitcoin daemon from which to retrieve this information amount: int; the minimum total amount (in Satoshi) Return value: tuple (total, inputs) total: int; the actual total amount (in Satoshi); total >= amount inputs: list of tuple (txid, vout, scriptPubKey, privateKey); the input information txid: str; input transaction ID. Note that the byte order is the reverse as shown in Bitcoin. vout: int; input transaction index scriptPubKey: str; input transaction scriptPubKey (serialized) privateKey: str; corresponding private key Exceptions: Exception: insufficient funds """ unspent = bitcoind.listUnspent() #Filter: only use "normal" outputs, not multisig etc. unspent = [u for u in unspent if "address" in u] #TODO: think about the best policy here. #Possible objectives: # - minimizing taint between addresses (privacy protection) # - minimizing coin fragmentation (transaction size, related to fee costs) # - choosing old coins (related to fee costs) #For now, an attempt is made to minimize coin fragmentation. unspent.sort(cmp=lambda a,b: cmp(a["amount"], b["amount"])) used = None total = 0 for u in unspent: if u["amount"] >= amount: used = [u] total = u["amount"] break if used is None: used = [] while total < amount: try: u = unspent.pop() except IndexError: raise Exception("Insufficient funds") used.append(u) total += u["amount"] for u in used: address = u["address"] u["privateKey"] = base58.decodeBase58Check( bitcoind.getPrivateKey(address), 128) return total, [ (u["txid"], u["vout"], u["scriptPubKey"], u["privateKey"]) for u in used]
def readPrivateKey(filename): with open(filename, "rb") as f: privateKey = f.read() privateKey = privateKey.split("\n")[0] #first line privateKey = privateKey.strip() #ignore whitespace return base58.decodeBase58Check(privateKey, 128) #PRIVKEY = 128
def spend(args): #Load the keys keys = [] for filename in args: privateKey = readPrivateKey(filename) k = Key() k.setPrivateKey(privateKey) keys.append(k) def getKey(question): for i in range(len(keys)): print i + 1, getAddress(keys[i]) i = int(raw_input(question)) - 1 return keys[i] #Ask for input information: inputs = [] amounts = [] while True: txid = raw_input("Transaction ID of unspent output (Enter to stop): ") txid = txid.strip() if txid == "": break txid = binascii.unhexlify(txid)[::-1] vout = int(raw_input("Output index of unspent output: ")) k = getKey("Address of unspent output: ") inputs.append((txid, vout, k)) amounts.append( int( decimal.Decimal(raw_input("Amount in unspent output (BCC): ")) * BCC)) totalAmount = sum(amounts) print "Total of amounts: %s BCC" % str(decimal.Decimal(totalAmount) / BCC) fee = int(decimal.Decimal(raw_input("Transaction fee (BCC): ")) * BCC) destAddress = raw_input("Destination address: ") destHash = base58.decodeBase58Check(destAddress, 0) #PUBKEY_ADDRESS = 0 destAmount = totalAmount - fee print "Amount sent to destination: %s BCC" % str( decimal.Decimal(destAmount) / BCC) if destAmount < 0: print "Negative amount is not allowed" sys.exit(2) ''' if destAmount > totalAmount - fee: print "Not enough funds" sys.exit(1) ''' tx = btx.Transaction( tx_in=[btx.TxIn(x[0], x[1]) for x in inputs], tx_out=[btx.TxOut(destAmount, btx.Script.standardPubKey(destHash))]) ''' changeKey = getKey("Address to send change amount to: ") changeAddress = getAddress(changeKey) changeHash = base58.decodeBase58Check(changeAddress, 0) #PUBKEY_ADDRESS = 0 changeAmount = totalAmount - destAmount - fee if changeAmount < 0: raise Exception("Error: got negative change amount") elif changeAmount == 0: print "Note: change amount is zero - no change is sent" else: tx.tx_out.append( btx.TxOut(changeAmount, btx.Script.standardPubKey(changeHash)) ) ''' for i in range(len(inputs)): #print tx.tx_in[i].previousOutputHash.encode("hex"), tx.tx_in[i].previousOutputIndex key = inputs[i][2] address = getAddress(key) hash = base58.decodeBase58Check(address, 0) #PUBKEY_ADDRESS = 0 scriptPubKey = btx.Script.standardPubKey(hash) tx.signInput(i, scriptPubKey, [None, key.getPublicKey()], [key], amounts[i]) print "Serialized transaction:" print tx.serialize().encode("hex") print "Transaction ID:", tx.getTransactionID()[::-1].encode("hex")
def decode(args): s = args[0] amounts = [int(decimal.Decimal(a) * BCC) for a in args[1:]] serialized = binascii.unhexlify(s) tx = btx.Transaction.deserialize(serialized) print 'lockTime: ', tx.lockTime for i in range(len(tx.tx_in)): tx_in = tx.tx_in[i] print 'TxIn:' print ' amount: %s BCC' % str(decimal.Decimal(amounts[i]) / BCC) print ' prevOutputHash: ', tx_in.previousOutputHash.encode("hex") print ' prevOutputIndex: ', tx_in.previousOutputIndex print ' sequenceNumber: 0x%08x' % tx_in.sequenceNumber print ' script:' for e in tx_in.scriptSig.elements: if isinstance(e, str): s = e.encode("hex") else: s = str(e) print ' ', s signature, pubKey = tx_in.scriptSig.elements hashType = ord(signature[-1]) signature = signature[:-1] k = Key() k.setPublicKey(pubKey) address = getAddress(k) hash = base58.decodeBase58Check(address, 0) #PUBKEY_ADDRESS = 0 scriptPubKey = btx.Script.standardPubKey(hash) sigHash = tx.getSignatureBodyHash(i, scriptPubKey, hashType, amount=amounts[i]) print ' pubKey: ', pubKey.encode('hex') print ' signature: ', signature.encode('hex') print ' hashType: 0x%0x' % hashType print ' address: ', address print ' sigHash: ', sigHash.encode('hex') print ' valid: ', k.verify(sigHash, signature) print '' for tx_out in tx.tx_out: print 'TxOut:' print ' amount: %s BCC' % str(decimal.Decimal(tx_out.amount) / BCC) elements = tx_out.scriptPubKey.elements print ' script:' for e in elements: if isinstance(e, str): s = e.encode("hex") else: s = '0x%0x' % e print ' ', s if len(elements) == 5 and \ elements[0:2] == [btx.OP.DUP, btx.OP.HASH160] and \ elements[3:5] == [btx.OP.EQUALVERIFY, btx.OP.CHECKSIG] and \ isinstance(elements[2], str): address = base58.encodeBase58Check(elements[2], 0) #PUBKEY_ADDRESS = 0 print ' Address: ', address else: print ' Unrecognized script type' print '' fee = sum(amounts) - sum([tx_out.amount for tx_out in tx.tx_out]) print 'Tx fee: %s BCC' % str(decimal.Decimal(fee) / BCC)
import base58 # translate Bitpay address format to traditional address format bitpay_address = 'CQ6BSmiDScwR3HX3pLaDdMjcMdz8byfKRo' public_key_hash = base58.decodeBase58Check(bitpay_address,28) trad_address = base58.encodeBase58Check(public_key_hash,0) print "Traditional Address: ", trad_address
import base58 # translate traditional address to Bitpay address format trad_address = '19oCM37SX7R7ctVPwv1pQ2RckTM3TmU9dS' public_key_hash = base58.decodeBase58Check(trad_address, 0) bitpay_address = base58.encodeBase58Check(public_key_hash, 28) print "Copay Address: ", bitpay_address