def build_bounce_tx(self, txid_hex): #Generate p2sh script pub key. redeem_script = self.fund_redeem_script(self.my) redeem_script_hash160 = self.hash160_script(redeem_script) txin_script_pub_key = CScript( [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) #Generate address to receive bounce. if "bounce" not in self.key_pairs: self.key_pairs["bounce"] = self.key_pair_from_address( self.jsonrpc[self.my].getnewaddress(), self.my) #Setup tx inputs and outputs. txid = lx(txid_hex) vout = 0 txin = CTxIn(COutPoint(txid, vout), CScript(), 0) #Sequence number 0. txout = CTxOut( (self.send_amount - decimal.Decimal(coinbend.config["mining_fee"]["standard"])) * COIN, CBitcoinAddress( self.key_pairs["bounce"]["addr"]["base58"]).to_scriptPubKey()) #Locktime is unsigned int 4, unix timestamp in little endian format. #(Conversion to little endian is handled by the library already.) nlock_time = datetime.datetime.now() + datetime.timedelta( seconds=self.future_minutes * 60) nlock_time = int(nlock_time.strftime("%s")) #Create unsigned transaction. tx = CTransaction([txin], [txout], nlock_time) return b2x(tx.serialize())
def spend_command(args): args.addr = CBitcoinAddress(args.addr) redeemScript = hodl_redeemScript(args.privkey, args.nLockTime) scriptPubKey = redeemScript.to_p2sh_scriptPubKey() proxy = bitcoin.rpc.Proxy() prevouts = [] for prevout in args.prevouts: try: txid, n = prevout.split(':') txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: args.parser.error('Invalid output: %s' % prevout) try: prevout = proxy.gettxout(outpoint) except IndexError: args.parser.error('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != scriptPubKey: args.parser.error('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for outpoint, prev_txout in prevouts) tx_size = ( 4 + # version field 2 + # # of txins len(prevouts) * 153 + # txins, including sigs 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) unsigned_tx = CTransaction( [CTxIn(outpoint, nSequence=0) for outpoint, prevout in prevouts], [CTxOut(sum_in - fees, args.addr.to_scriptPubKey())], args.nLockTime) signed_tx = CTransaction([ CTxIn(txin.prevout, spend_hodl_redeemScript(args.privkey, args.nLockTime, unsigned_tx, i), nSequence=0) for i, txin in enumerate(unsigned_tx.vin) ], unsigned_tx.vout, unsigned_tx.nLockTime) print(b2x(signed_tx.serialize()))
def recover_command(args): args.fee_per_kb = int(args.fee_per_kb * COIN) addr = CBitcoinAddress(args.addr) tx = CTransaction() sum_value_in = 0 dummy_scriptSig = CScript([b'\x00'*74]) inputs = {} for outpoint, txout in tuple(args.wallet.unspent_txouts.items())[0:500]: sum_value_in += txout.nValue tx.vin.append(CTxIn(outpoint, dummy_scriptSig)) inputs[outpoint] = txout tx.vout.append(CTxOut(-1, addr.to_scriptPubKey())) fees = int((len(tx.serialize())/1000) * args.fee_per_kb) tx.vout[0].nValue = sum_value_in - fees # Sign the transaction for (i, txin) in enumerate(tx.vin): prevout_scriptPubKey = inputs[txin.prevout].scriptPubKey sighash = SignatureHash(prevout_scriptPubKey, tx, i, SIGHASH_ALL) seckey = args.wallet.keypairs[prevout_scriptPubKey] sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) if prevout_scriptPubKey[-1] == OP_CHECKMULTISIG: txin.scriptSig = CScript([OP_0, sig]) elif prevout_scriptPubKey[-1] == OP_CHECKSIG and prevout_scriptPubKey[-2] == OP_EQUALVERIFY: txin.scriptSig = CScript([sig, seckey.pub]) VerifyScript(txin.scriptSig, prevout_scriptPubKey, tx, i) print(b2x(tx.serialize()))
def spend_command(pubkey, nLockTime, prevOuts): addr = P2PKHBitcoinAddress.from_pubkey(x(pubkey)) address = addr redeemScript = hodl_redeemScript(pubkey, nLockTime) scriptPubKey = redeemScript.to_p2sh_scriptPubKey() proxy = bitcoin.rpc.Proxy(btc_conf_file=bitcoin.params.CONF_FILE) prevouts = [] for prevout in prevOuts: try: txid, n = prevout.split(':') txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: raise Exception('Invalid output: %s' % prevout) try: prevout = proxy.gettxout(outpoint) except IndexError: raise Exception('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != scriptPubKey: raise Exception('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for outpoint, prev_txout in prevouts) tx_size = ( 4 + # version field 2 + # number of txins len(prevouts) * 153 + # txins, including sigs 1 + # number of txouts 34 + # txout 4) # nLockTime field feerate = int(proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) unsigned_tx = CTransaction([ CTxIn(outpoint, redeemScript, nSequence=0) for outpoint, prevout in prevouts ], [CTxOut(sum_in - fees, address.to_scriptPubKey())], nLockTime) return ({'redeemTransaction': b2x(unsigned_tx.serialize())})
def SignatureHash(script, txTo, inIdx, hashtype): if inIdx >= len(txTo.vin): return (1, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) txtmp = CTransaction() txtmp.copy(txTo) for txin in txtmp.vin: txin.scriptSig = b'' txtmp.vin[inIdx].scriptSig = script.vch if (hashtype & 0x1f) == SIGHASH_NONE: txtmp.vout = [] for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 elif (hashtype & 0x1f) == SIGHASH_SINGLE: outIdx = inIdx if outIdx >= len(txtmp.vout): return (1, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) tmp = txtmp.vout[outIdx] txtmp.vout = [] for i in range(outIdx): txtmp.vout.append(CTxOut()) txtmp.vout.append(tmp) for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 if hashtype & SIGHASH_ANYONECANPAY: tmp = txtmp.vin[inIdx] txtmp.vin = [] txtmp.vin.append(tmp) s = txtmp.serialize() s += struct.pack(b"<I", hashtype) hash = Hash(s) return (hash, )
def SignatureHash(script, txTo, inIdx, hashtype): if inIdx >= len(txTo.vin): return (0, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) txtmp = CTransaction() txtmp.copy(txTo) for txin in txtmp.vin: txin.scriptSig = b'' txtmp.vin[inIdx].scriptSig = script.vch if (hashtype & 0x1f) == SIGHASH_NONE: txtmp.vout = [] for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 elif (hashtype & 0x1f) == SIGHASH_SINGLE: outIdx = inIdx if outIdx >= len(txtmp.vout): return (0, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) tmp = txtmp.vout[outIdx] txtmp.vout = [] for i in range(outIdx): txtmp.vout.append(CTxOut()) txtmp.vout.append(tmp) for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 if hashtype & SIGHASH_ANYONECANPAY: tmp = txtmp.vin[inIdx] txtmp.vin = [] txtmp.vin.append(tmp) s = txtmp.serialize() s += struct.pack(b"<I", hashtype) hash = Hash(s) return (hash,)
def build_claim_tx(self, txid_hex): if self.secret_info["plaintext"] == None: raise Exception("We don't know the secret yet.") #Create redeem script. redeem_script = self.fund_redeem_script(self.their) #Convert to p2sh address. their_fund_address = self.script_to_address(redeem_script, self.their) #Check there is enough in the p2sh address. their_fund_tx = self.jsonrpc[self.their].gettransaction( txid_hex)["details"] found = 0 for tx_input in their_fund_tx: #Check it's the right input. if tx_input["address"] == their_fund_address: found = 1 if tx_input["amount"] + self.recv_amount > decimal.Decimal( coinbend.config["mining_fee"]["standard"]): raise Exception( "Their contract has not been sufficently funded.") break else: continue #Their side of the contract hasn't been funded. if not found: raise Exception("Their contract fund output was not detected.") #Generate address to receive redeemed output. if "receive" not in self.key_pairs: self.key_pairs["receive"] = self.key_pair_from_address( self.jsonrpc[self.their].getnewaddress(), self.their) #Load private key for signing. seckey = CBitcoinSecret(self.key_pairs[self.my]["priv"]["wif"]) #Generate p2sh script pub key. redeem_script_hash160 = self.hash160_script(redeem_script) txin_script_pub_key = CScript( [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) #Setup tx inputs and outputs. txid = lx(txid_hex) vout = 0 txin = CTxIn(COutPoint(txid, vout)) txout = CTxOut( (self.recv_amount - decimal.Decimal(coinbend.config["mining_fee"]["standard"])) * COIN, CBitcoinAddress( self.key_pairs["receive"]["addr"]["base58"]).to_scriptPubKey()) #Create unsigned transaction. tx = CTransaction([txin], [txout]) #Sign transactions. sighash = SignatureHash(redeem_script["bin"], tx, 0, SIGHASH_ALL) sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) txin.scriptSig = CScript([ bytes(self.secret_info["plaintext"].encode("ascii")), sig, OP_3, redeem_script["bin"] ]) #Return signed transaction hex. return b2x(tx.serialize())
def build_fund_tx(self, redeem_script): if type(self.send_amount) != decimal.Decimal: raise Exception("Please only use decimal types for the amount.") if self.send_amount < decimal.Decimal( coinbend.config["minimum_trade"]): raise Exception("Amount is too small.") #Because every Satoshi counts. decimal.getcontext().prec = 50 #Create a change address. if "change" not in self.key_pairs: self.key_pairs["change"] = self.key_pair_from_address( self.jsonrpc[self.my].getnewaddress(), self.my) #Get wallet balance. balance = self.jsonrpc[self.my].getbalance() #Check we have enough. if balance < self.send_amount: raise Exception("Insufficent balance to cover fund.") #List unclaimed outputs. unspent_outputs = self.jsonrpc[self.my].listunspent() #Setup tx inputs. change_amount = decimal.Decimal("0") txins = [] total = decimal.Decimal("0") indexes = [] i = 0 for unspent_output in unspent_outputs: #Skip outputs that don't satisfy min confirmations. if unspent_output["confirmations"] < self.minimum_confirmations: i += 1 continue #Check scriptPubKey is pay to pub key hash. if self.jsonrpc[self.my].decodescript( unspent_output["scriptPubKey"])["type"] != "pubkeyhash": i += 1 continue #Record key pairs. if unspent_output["address"] not in self.key_pairs: self.key_pairs[ unspent_output["address"]] = self.key_pair_from_address( unspent_output["address"], self.my) #Build new txin. txid = lx(unspent_output["txid"]) vout = unspent_output["vout"] txin = CTxIn(COutPoint(txid, vout)) txins.append(txin) indexes.append(i) total += unspent_output["amount"] i += 1 if total > self.send_amount: break if total == self.send_amount: break #Insufficent funds. if total < self.send_amount: raise Exception("Not enough valid inputs to fund contract.") #Calculate change. change = total - self.send_amount #Build txouts. txouts = [] redeem_script_hash160 = self.hash160_script(redeem_script) p2sh_script_pub_key = CScript( [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) txouts.append( CTxOut( (self.send_amount - decimal.Decimal(coinbend.config["mining_fee"]["standard"])) * COIN, p2sh_script_pub_key)) if change > decimal.Decimal("0"): change_seckey = CBitcoinSecret( self.key_pairs["change"]["priv"]["wif"]) change_script_pub_key = CScript([ OP_DUP, OP_HASH160, Hash160(change_seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG ]) txouts.append(CTxOut(change * COIN, change_script_pub_key)) #Build unsigned transaction. tx = CTransaction(txins, txouts) unsigned_tx_hex = b2x(tx.serialize()) #Sign transaction. signed_tx_hex = self.jsonrpc[self.my].signrawtransaction( unsigned_tx_hex)["hex"] return signed_tx_hex
# address. txout = CTxOut(0.0005*COIN, CBitcoinAddress('323uf9MgLaSn9T7vDaK1cGAZ2qpvYUuqSp').to_scriptPubKey()) # Create the unsigned transaction. tx = CTransaction([txin],[txout]) # Calculate the signature hash for that transaction. Note how the script we use # is the redeemScript, not the scriptPubKey. That's because when the CHECKSIG # operation happens EvalScript() will be evaluating the redeemScript, so the # corresponding SignatureHash() function will use that same script when it # replaces the scriptSig in the transaction being hashed with the script being # executed. sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL) # Now sign it. We have to append the type of signature we want to the end, in # this case the usual SIGHASH_ALL. sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) # Set the scriptSig of our transaction input appropriately. txin.scriptSig = CScript([sig, txin_redeemScript]) # Verify the signature worked. This calls EvalScript() and actually executes # the opcodes in the scripts to see if everything worked out. If it doesn't an # exception will be raised. print(b2x(txin_scriptPubKey)) VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) # Done! Print the transaction to standard output with the bytes-to-hex # function. print(b2x(tx.serialize()))
def build_setup(self): #Get wallet balance. currency = self.trade.to_send.currency coin_rpc = self.coins[currency]["rpc"]["sock"] balance = C(coin_rpc.getbalance()) self.tx_fee_amount = self.coins[currency]["tx_fee"] #Check we have enough. if balance < self.trade.to_send: raise Exception("Insufficent balance to cover fund.") #List unclaimed inputs. self.green_address.load_inputs() unspent_inputs = self.green_address.inputs #Check unclaimed outputs go to the right green address. deposit_tx = self.green_address.deposit_tx_hex print(deposit_tx) deposit_tx = CTransaction.deserialize(binascii.unhexlify(deposit_tx)) print(deposit_tx) ret = parse_address(None, deposit_tx, currency) print(ret) ret = ret[0] print(ret) if ret["type"] != "p2sh": raise Exception("Invalid green address deposit tx.") else: p2sh_index = ret["vout"] green_address_hash = deconstruct_address(self.green_address.address)["hash"] if deposit_tx.vout[p2sh_index].scriptPubKey != CScript([OP_HASH160, green_address_hash, OP_EQUAL]): raise Exception("Unexpected green address output.") #Setup tx inputs. txins = [] green_total = C("0") indexes = [] for unspent_input in unspent_inputs: #Skip outputs that don't satisfy min confirmations. confirmations = int(self.config["confirmations"]) if unspent_input["confirmations"] < confirmations: continue #Skip non p2sh outputs. if unspent_input["vout"] != p2sh_index: continue #Build new txin. txid = lx(unspent_input["txid"]) vout = unspent_input["vout"] txin = CTxIn(COutPoint(txid, vout)) txins.append(txin) green_total += C(unspent_input["amount"]) break #Insufficent funds. if green_total < self.green_address.trade.to_send: print("Exception .. insufficent funds.") print(green_total) print(self.green_address.trade.to_send) raise Exception("Not enough valid inputs to fund contract.") #Calculate collateral amount. total = C(0) collateral = C(0) to_send = C(0) for contract_hash in list(self.contracts): contract = self.contracts[contract_hash] collateral += contract.our_chunk_size to_send += contract.upload_amount + contract.our_chunk_size + self.tx_fee_amount print("Our chunk size: " + str(contract.our_chunk_size)) """ Trade fees are initially applied based on being able to match 100%. If there's change it means not everything was matched and hence you're being charged fees for coins that aren't even being traded. The code bellow recalculates the fees. """ fees = self.trade.fees to_send += fees if to_send < self.green_address.trade.to_send: print("Fees reduced.") ceiling = self.green_address.trade.to_send - to_send fees = ceiling * self.trade_fee #I'm not sure this is correct. print("Trade fees: " + str(fees)) #Add fees to collateral. collateral += fees print("Collateral: " + str(collateral)) total += collateral #Collateral / fee output. txouts = [] ecdsa_fee = ECDSACrypt(self.config["fee_key_pair"]["pub"]) collateral_script_pub_key = CScript([OP_DUP, OP_HASH160, Hash160(ecdsa_fee.get_public_key("bin")), OP_EQUALVERIFY, OP_CHECKSIG]) txouts.append(CTxOut(collateral.as_decimal * COIN, collateral_script_pub_key)) #Contract outputs. for contract_hash in list(self.contracts): contract = self.contracts[contract_hash] redeem_script = bond_redeem_script(contract.ecdsa_us, contract.ecdsa_them, self.ecdsa_arbiters[0]) redeem_script_hash160 = hash160_script(redeem_script) p2sh_script_pub_key = CScript([OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) contract_amount = contract.upload_amount + self.tx_fee_amount print("Contract amount: " + str(contract_amount)) txouts.append(CTxOut(contract_amount.as_decimal * COIN, p2sh_script_pub_key)) total += contract_amount #Change output. if total < self.green_address.trade.to_send: change = self.green_address.trade.to_send - total if change > C("0"): change_script_pub_key = CScript([OP_DUP, OP_HASH160, Hash160(self.ecdsa_1.get_public_key("bin")), OP_EQUALVERIFY, OP_CHECKSIG]) txouts.append(CTxOut(change.as_decimal * COIN, change_script_pub_key)) #Build unsigned transaction. tx = CTransaction(txins, txouts) #Return unsigned transaction hex. tx_hex = b2x(tx.serialize()) txid = calculate_txid(tx_hex) our_first_sig = sign_setup_tx(tx_hex, self.green_address.redeem_script, self.green_address.ecdsa_1) our_second_sig = sign_setup_tx(tx_hex, self.green_address.redeem_script, self.green_address.ecdsa_2) self.setup["tx_hex"] = tx_hex self.setup["txid"] = txid self.setup["sig_1"] = our_first_sig self.setup["sig_2"] = our_second_sig return { "tx_hex": tx_hex, "txid": txid, "first_sig": our_first_sig, "second_sig": our_second_sig }
tx = CTransaction() # get the outpoint from which we want to spend previous.hash = 0xeccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2 previous.n = 0x01000000 txin.prevout = previous txin.scriptSig = binascii.unhexlify("76a914010966776006953d5567439e5e39f86a0d273bee88ac") # create output transaction txout.nValue = 0x605af40500000000 txout.scriptPubKey = binascii.unhexlify("76a914097072524438d003d23a2f23edb65aae1bb3e46988ac") # set inputs and outputs tx.vin.append(txin) tx.vout.append(txout) sertx = tx.serialize() + binascii.unhexlify("01000000") """ print sertx[:76] print sertx[76:152] print sertx[152:] """ dhash = myhash(sertx) print binascii.hexlify(dhash) print "9302bda273a887cb40c13e02a50b4071a31fd3aae3ae04021b0b843dd61ad18e" # sign the transaction now print "\n\n" x = """
txout_info = proxy.gettxout(txin.prevout) except IndexError: print('Already spent! line %d, txid %s %d' % \ (line, b2lx(txin.prevout.hash), txin.prevout.n), file=sys.stderr) continue print('line %d: %s %d: %s' % \ (line, b2lx(txin.prevout.hash), txin.prevout.n, str_money_value(txout_info['txout'].nValue)), file=sys.stderr) sum_value_in += txout_info['txout'].nValue if txin.prevout not in prevouts: prevouts.add(txin.prevout) txins.append(txin) else: print('Dup! line %d, txid %s %d' % \ (line, b2lx(txin.prevout.hash), txin.prevout.n), file=sys.stderr) random.shuffle(txins) tx = CTransaction(txins, [CTxOut(0, CScript([OP_RETURN]))]) print(b2x(tx.serialize())) print('Total: %s Size: %d' % (str_money_value(sum_value_in), len(tx.serialize())), file=sys.stderr)
for txin in tx.vin: try: txout_info = proxy.gettxout(txin.prevout) except IndexError: print('Already spent! line %d, txid %s %d' % \ (line, b2lx(txin.prevout.hash), txin.prevout.n), file=sys.stderr) continue print('line %d: %s %d: %s' % \ (line, b2lx(txin.prevout.hash), txin.prevout.n, str_money_value(txout_info['txout'].nValue)), file=sys.stderr) sum_value_in += txout_info['txout'].nValue if txin.prevout not in prevouts: prevouts.add(txin.prevout) txins.append(txin) else: print('Dup! line %d, txid %s %d' % \ (line, b2lx(txin.prevout.hash), txin.prevout.n), file=sys.stderr) random.shuffle(txins) tx = CTransaction(txins, [CTxOut(0, CScript([OP_RETURN]))]) print(b2x(tx.serialize())) print('Total: %s Size: %d' % (str_money_value(sum_value_in), len(tx.serialize())), file=sys.stderr)
def attack_command(args): #args.starting_height = 2**32-1 #scan_command(args) fd = open('sent-txs','a') for txhash in args.rpc.getrawmempool(): txhash = lx(txhash) tx = args.rpc.getrawtransaction(txhash) args.wallet.scan_tx(tx) args.fee_per_kb = int(args.fee_per_kb * COIN) # deque of transaction outputs, (COutPoint, CTxOut), that we have available # to spend. We use these outputs in order, oldest first. available_txouts = collections.deque() # gather up existing outputs total_funds = 0 for outpoint, txout in args.wallet.unspent_txouts.items(): total_funds += txout.nValue available_txouts.append((outpoint, txout)) size_sent = 0 while available_txouts: logging.info('Attacking! Sent %d bytes total, Funds left: %s in %d txouts' % (size_sent, str_money_value(total_funds), len(available_txouts))) tx = CTransaction() # Gather up txouts until we have enough funds in to pay the fees on a # target-sized tx as well as the non-dust outputs. sum_value_in = 0 # Assuming the whole tx is CTxOut's, each one is 46 bytes (1-of-1 # CHECKMULTISIG) and the value out needs to be at least 1000 satoshis. avg_txout_size = 46 #25+1+8 num_txouts = args.target_tx_size // avg_txout_size min_value_out = 10000 sum_min_value_out = num_txouts * min_value_out fees = (args.target_tx_size/1000) * args.fee_per_kb inputs = {} tx_size = len(tx.serialize()) dummy_scriptSig = CScript([b'\x00'*74]) while (sum_value_in < fees + sum_min_value_out and tx_size < args.target_tx_size/2 # don't devote more than half the tx to inputs and available_txouts): outpoint, txout = available_txouts.popleft() try: args.rpc.gettxout(outpoint) except IndexError: continue inputs[outpoint] = txout sum_value_in += txout.nValue # The CTxIn has a dummy signature so size calculations will be right txin = CTxIn(outpoint, dummy_scriptSig) tx.vin.append(txin) tx_size += len(txin.serialize()) total_funds -= sum_value_in # Recalculate number of txouts we'll have now that we've added the # txins. Of course, this will leave the actual value per txout a bit # high, but whatever. num_txouts = int(min((args.target_tx_size-len(tx.serialize())) / avg_txout_size, (sum_value_in - fees) / min_value_out)) # Split the funds out evenly among all transaction outputs. per_txout_value = (sum_value_in - fees) // num_txouts for i in range(num_txouts): scriptPubKey = args.wallet.make_multisig() txout = CTxOut(per_txout_value, scriptPubKey) tx.vout.append(txout) # Sign the transaction for (i, txin) in enumerate(tx.vin): prevout_scriptPubKey = inputs[txin.prevout].scriptPubKey sighash = SignatureHash(prevout_scriptPubKey, tx, i, SIGHASH_ALL) seckey = args.wallet.keypairs[prevout_scriptPubKey] sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) if prevout_scriptPubKey[-1] == OP_CHECKMULTISIG: txin.scriptSig = CScript([OP_0, sig]) elif prevout_scriptPubKey[-1] == OP_CHECKSIG and prevout_scriptPubKey[-2] == OP_EQUALVERIFY: txin.scriptSig = CScript([sig, seckey.pub]) VerifyScript(txin.scriptSig, prevout_scriptPubKey, tx, i) # Add the new txouts to the list of available txouts tx_hash = tx.get_hash() sum_value_out = 0 for i, txout in enumerate(tx.vout): outpoint = COutPoint(tx_hash, i) available_txouts.append((outpoint, txout)) sum_value_out += txout.nValue total_funds += sum_value_out actual_fees = sum_value_in - sum_value_out serialized_tx = tx.serialize() logging.debug('Sending tx %s\n' ' value in: %s, value out: %s, fees: %s, fees/KB: %s\n' ' size: %d, # of inputs: %d, # of outputs: %d, txout.nValue: %s' % (b2lx(tx_hash), str_money_value(sum_value_in), str_money_value(sum_value_out), str_money_value(actual_fees), str_money_value(actual_fees/(len(serialized_tx)/1000)), len(serialized_tx), len(tx.vin), len(tx.vout), per_txout_value)) size_sent += len(serialized_tx) #print(b2x(serialized_tx)) #args.wallet.save() try: args.rpc.sendrawtransaction(tx) fd.write(b2x(serialized_tx) + '\n') fd.flush() except bitcoin.rpc.JSONRPCException as exp: print(b2x(tx.serialize())) #import pdb; pdb.set_trace() time.sleep(random.randrange(30,60))
def build_refund_tx(self, setup_tx_id, refund_amount=None): #Check refund amount. if refund_amount != None: if refund_amount > self.trade.to_send: raise Exception("Invalid refund amount.") #Create redeem script. redeem_script = bond_redeem_script(self.ecdsa_us, self.ecdsa_them, self.factory.ecdsa_arbiters[0]) #Generate p2sh script pub key. redeem_script_hash160 = hash160_script(redeem_script) txin_script_pub_key = CScript([OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) #Setup tx inputs. txid = lx(setup_tx_id) txin = CTxIn(COutPoint(txid, self.vout)) txouts = [] #Our output. our_address = deconstruct_address(self.change_address)["hash"] our_pub_key = CScript([OP_DUP, OP_HASH160, our_address, OP_EQUALVERIFY, OP_CHECKSIG]) #Their output. their_address = deconstruct_address(self.their_address)["hash"] their_pub_key = CScript([OP_DUP, OP_HASH160, their_address, OP_EQUALVERIFY, OP_CHECKSIG]) #Append outputs. if refund_amount == None: #Inital full refund. remaining = self.upload_amount txouts.append(CTxOut(remaining.as_decimal * COIN, our_pub_key)) else: """ Micro-payment channel i.e. the contract. The refund amount leaves "room" for a TX fee so you just do normal calculations and the difference constitutes the TX fee. """ remaining = self.upload_amount - refund_amount if remaining > C("0"): txouts.append(CTxOut(remaining.as_decimal * COIN, our_pub_key)) txouts.append(CTxOut(refund_amount.as_decimal * COIN, their_pub_key)) #Create unsigned transaction. if refund_amount == None: txin.nSequence = 0 #Enable ntimelocks. tx = CTransaction([txin], txouts, self.nlock_time) else: txin.nSequence = 0xffffffff #Make transaction final! tx = CTransaction([txin], txouts) #Return unsigned transaction hex. tx_hex = b2x(tx.serialize()) txid = calculate_txid(tx_hex) our_first_sig = self.sign_refund_tx(tx_hex, 1) our_second_sig = self.sign_refund_tx(tx_hex, 2) return { "tx_hex": tx_hex, "txid": txid, "first_sig": our_first_sig, "second_sig": our_second_sig }
txout = CTxOut( 0.0005 * COIN, CBitcoinAddress('323uf9MgLaSn9T7vDaK1cGAZ2qpvYUuqSp').to_scriptPubKey()) # Create the unsigned transaction. tx = CTransaction([txin], [txout]) # Calculate the signature hash for that transaction. Note how the script we use # is the redeemScript, not the scriptPubKey. That's because when the CHECKSIG # operation happens EvalScript() will be evaluating the redeemScript, so the # corresponding SignatureHash() function will use that same script when it # replaces the scriptSig in the transaction being hashed with the script being # executed. sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL) # Now sign it. We have to append the type of signature we want to the end, in # this case the usual SIGHASH_ALL. sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) # Set the scriptSig of our transaction input appropriately. txin.scriptSig = CScript([sig, txin_redeemScript]) # Verify the signature worked. This calls EvalScript() and actually executes # the opcodes in the scripts to see if everything worked out. If it doesn't an # exception will be raised. VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH, )) # Done! Print the transaction to standard output with the bytes-to-hex # function. print(b2x(tx.serialize()))
def settle_to_single_addr(deposits: List[Deposit], addr: CBitcoinAddress): prevouts = [] for d in deposits: try: txid, n = d.txid, d.nout txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: raise ValueError('Invalid output: %s' % d) try: prevout = proxy.gettxout(outpoint) except IndexError: raise ValueError('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != d.params.deposit_redeemScript.to_p2sh_scriptPubKey( ): raise Exception('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for _, prev_txout in prevouts) tx_size = ( 4 + # version field 2 + # # of txins len(prevouts) * 153 + # txins, including sigs 1 + # # of txouts 34 + # txout 4 # nLockTime field ) estimated_fee = proxy._call('estimatesmartfee', 1) if 'errors' in estimated_fee: print(estimated_fee['errors']) feerate = -1 else: feerate = int(estimated_fee['feerate'] * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) print('fee: %f' % fees) print('amount: %f' % (sum_in - fees)) # lock until the next block nLockTime = proxy.getblockcount() unsigned_tx = CTransaction( [CTxIn(outpoint, nSequence=0) for outpoint, _ in prevouts], [CTxOut(sum_in - fees, addr.to_scriptPubKey())], nLockTime=nLockTime) # sign the inputs signed_ins = [ CTxIn(unsigned_tx.vin[i].prevout, d.params.spend_redeemScript('exch', exch_seckey, unsigned_tx, i), nSequence=0) for i, d in enumerate(deposits) ] signed_tx = CTransaction(signed_ins, unsigned_tx.vout, unsigned_tx.nLockTime) print(b2x(signed_tx.serialize()))
def spend_command(args): args.addr = CBitcoinAddress(args.addr) redeemScript = hodl_redeemScript(args.privkey, args.nLockTime) scriptPubKey = redeemScript.to_p2sh_scriptPubKey() proxy = bitcoin.rpc.Proxy() prevouts = [] for prevout in args.prevouts: try: txid,n = prevout.split(':') txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: args.parser.error('Invalid output: %s' % prevout) try: prevout = proxy.gettxout(outpoint) except IndexError: args.parser.error('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != scriptPubKey: args.parser.error('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for outpoint,prev_txout in prevouts) tx_size = (4 + # version field 2 + # # of txins len(prevouts) * 153 + # txins, including sigs 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) unsigned_tx = CTransaction([CTxIn(outpoint, nSequence=0) for outpoint, prevout in prevouts], [CTxOut(sum_in - fees, args.addr.to_scriptPubKey())], args.nLockTime) signed_tx = CTransaction( [CTxIn(txin.prevout, spend_hodl_redeemScript(args.privkey, args.nLockTime, unsigned_tx, i), nSequence=0) for i, txin in enumerate(unsigned_tx.vin)], unsigned_tx.vout, unsigned_tx.nLockTime) print(b2x(signed_tx.serialize()))
CScript([1, x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71'), b'\x00'*33, 2, OP_CHECKMULTISIG])) tx.vout.append(multisig_txout) for bad_addr in args.bad_addr: bad_addr = CBitcoinAddress(bad_addr) txout = CTxOut(args.dust, bad_addr.to_scriptPubKey()) tx.vout.append(txout) # Add inputs until we meet the fee1 threshold unspent = sorted(rpc.listunspent(1), key=lambda x: x['amount']) value_in = 0 value_out = sum([vout.nValue for vout in tx.vout]) while (value_in - value_out) / len(tx.serialize()) < feeperbyte1: # What's the delta fee that we need to get to our desired fees per byte at # the current tx size? delta_fee = math.ceil((feeperbyte1 * len(tx.serialize())) - (value_in - value_out)) logging.debug('Delta fee: %s' % str_money_value(delta_fee)) # If we simply subtract that from the change outpoint are we still above # the dust threshold? if change_txout.nValue - delta_fee > args.dust: change_txout.nValue -= delta_fee value_out -= delta_fee # Do we need to add another input? if value_in - value_out < 0: new_outpoint = unspent[-1]['outpoint']
# get the outpoint from which we want to spend previous.hash = 0xeccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2 previous.n = 0x01000000 txin.prevout = previous txin.scriptSig = binascii.unhexlify( "76a914010966776006953d5567439e5e39f86a0d273bee88ac") # create output transaction txout.nValue = 0x605af40500000000 txout.scriptPubKey = binascii.unhexlify( "76a914097072524438d003d23a2f23edb65aae1bb3e46988ac") # set inputs and outputs tx.vin.append(txin) tx.vout.append(txout) sertx = tx.serialize() + binascii.unhexlify("01000000") """ print sertx[:76] print sertx[76:152] print sertx[152:] """ dhash = myhash(sertx) print binascii.hexlify(dhash) print "9302bda273a887cb40c13e02a50b4071a31fd3aae3ae04021b0b843dd61ad18e" # sign the transaction now print "\n\n" x = """ 0100000001eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f201