def testSendtoaddress(self): # Send 1 BTC serializedUnsignedTx = \ self.jsonServer.jsonrpc_createustxtoaddress(TIAB_WLT_3_ADDR_3, \ BTC_TO_SEND) unsignedTx = UnsignedTransaction().unserializeAscii( serializedUnsignedTx) # Should have 2 txouts to TIAB_WLT_3_ADDR_3 and the change self.assertEqual(len(unsignedTx.decorTxOuts), 2) foundTxOut = False for txout in unsignedTx.decorTxOuts: if script_to_addrStr(txout.binScript) == TIAB_WLT_3_ADDR_3: self.assertEqual(txout.value, JSONtoAmount(BTC_TO_SEND)) foundTxOut = True self.assertTrue(foundTxOut) # Test two paths through signing method and make sure they are equal # Wallets in the TIAB start out unencrypted f = open(TX_FILENAME, 'w') f.write(serializedUnsignedTx) f.close() serializedSignedTxUnencrypted = \ self.jsonServer.jsonrpc_signasciitransaction(TX_FILENAME) self.jsonServer.jsonrpc_encryptwallet(PASSPHRASE1) self.jsonServer.jsonrpc_walletpassphrase(PASSPHRASE1) serializedSignedTxEncrypted = \ self.jsonServer.jsonrpc_signasciitransaction(TX_FILENAME) # Other tests expect wallet to be unencrypted self.wltA.unlock(securePassphrase=SecureBinaryData(PASSPHRASE1), tempKeyLifetime=1000000) self.wltA.changeWalletEncryption() signedTxUnencrypted = UnsignedTransaction().unserializeAscii( serializedSignedTxUnencrypted) signedTxEncrypted = UnsignedTransaction().unserializeAscii( serializedSignedTxEncrypted) # check number of outputs 1 Btc goes to a single output and the other goes to change self.assertEqual(len(signedTxUnencrypted.decorTxOuts), 2) self.assertEqual(len(signedTxEncrypted.decorTxOuts), 2) self.assertEqual(signedTxUnencrypted.asciiID, signedTxEncrypted.asciiID) self.assertTrue( JSONtoAmount(BTC_TO_SEND) in [ signedTxEncrypted.decorTxOuts[0].value, signedTxEncrypted.decorTxOuts[1].value ]) self.assertTrue( JSONtoAmount(BTC_TO_SEND) in [ signedTxUnencrypted.decorTxOuts[0].value, signedTxUnencrypted.decorTxOuts[1].value ]) f = open(TX_FILENAME, 'w') f.write(signedTxEncrypted.serializeAscii()) f.close() txHexToBroadcast = self.jsonServer.jsonrpc_gethextxtobroadcast( TX_FILENAME) finalPyTx = PyTx().unserialize(hex_to_binary(txHexToBroadcast)) self.assertEqual(len(finalPyTx.outputs), 2) self.assertTrue( JSONtoAmount(BTC_TO_SEND) in [finalPyTx.outputs[0].value, finalPyTx.outputs[1].value])
def sweepImportedAddrs(masterWallet): setupTheBDM() recipValuePairs = [] utxoList = [] for importedAddr in masterWallet.getLinearAddrList(): if importedAddr.chainIndex<0: addr160 = importedAddr.getAddr160() utxoList.extend(masterWallet.getAddrTxOutList(addr160)) # get total value totalAvailable = sum([u.getValue() for u in utxoList]) fee = calcMinSuggestedFees(utxoList, totalAvailable, MIN_RELAY_TX_FEE, 1)[1] totalSpend = totalAvailable - fee if totalSpend<0: print '***ERROR: The fees are greater than the funds being swept!' raise NegativeValueError recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalSpend )) # ACR: To support P2SH in general, had to change createFromTxOutSelection # to take full scripts, not just hash160 values. Convert the list # before passing it in scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs] ustx = UnsignedTransaction().createFromTxOutSelection(utxoList, scrPairs) masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:'))) # Sign and prepare the final transaction for broadcast masterWallet.signTxDistProposal(ustx) pytx = ustx.getPyTxSignedIfPossible() print '\nSigned transaction to be broadcast using Armory "offline transactions"...' print ustx.serializeAscii() return pytx
def __init__(self, main, pytxOrUstx, setSignerFunc): self.main = main self.setSignerFunc = setSignerFunc self.ustx = pytxOrUstx if pytxOrUstx != None and isinstance(pytxOrUstx, PyTx): self.ustx = UnsignedTransaction() self.ustx.createFromPyTx(pytxOrUstx) self.frmSigner = QFrame() self.frmSigner.setFrameStyle(STYLE_RAISED) frmSignerLayout = QGridLayout() signerLabel = QLabel(self.main.tr('Signer: ')) signerLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.typeLabel = QLabelButton("") self.typeLabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.originalType = SIGNER_DEFAULT if self.ustx != None: self.originalType = self.ustx.signerType self.setType(self.originalType) setSignerFunc(self.originalType) self.main.connect(self.typeLabel, SIGNAL('clicked()'), self.changeType) frmSignerLayout.addWidget(signerLabel, 0, 0, 1, 1) frmSignerLayout.addWidget(self.typeLabel, 0, 1, 1, 2) self.frmSigner.setLayout(frmSignerLayout)
def distributeBtc(masterWallet, amount, sendingAddrList): pytx = None setupTheBDM() try: recipValuePairs = [] utxoList = [] for sendingAddr in sendingAddrList: addr160 = sendingAddr.getAddr160() # Make sure the sending addresses are in the masterWallet if not masterWallet.hasAddr(addr160): raise WalletAddressError, 'Address is not in wallet! [%s]' % sendingAddr.getAddrStr() utxoList.extend(masterWallet.getAddrTxOutList(addr160)) for importedAddr in masterWallet.getLinearAddrList(): if importedAddr.chainIndex<0: recipValuePairs.append((importedAddr.getAddr160(),amount)) totalSpend = len(recipValuePairs)*amount fee = calcMinSuggestedFees(utxoList, totalSpend, MIN_RELAY_TX_FEE, len(recipValuePairs))[1] # Get the necessary utxo list selectedUtxoList = PySelectCoins(utxoList, totalSpend, fee) # get total value totalAvailable = sum([u.getValue() for u in selectedUtxoList]) totalChange = totalAvailable - (totalSpend + fee) # Make sure there are funds to cover the transaction. if totalChange < 0: print '***ERROR: you are trying to spend more than your balance!' raise NegativeValueError recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalChange )) # ACR: To support P2SH in general, had to change createFromTxOutSelection # to take full scripts, not just hash160 values. Convert the list # before passing it in scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs] # we're providing a key map for the inputs. pubKeyMap = {} for utxo in selectedUtxoList: scrType = getTxOutScriptType(utxo.getScript()) if scrType in CPP_TXOUT_STDSINGLESIG: scrAddr = utxo.getRecipientScrAddr() a160 = scrAddr_to_hash160(scrAddr)[1] addrObj = masterWallet.getAddrByHash160(a160) if addrObj: pubKeyMap[scrAddr] = addrObj.binPublicKey65.toBinStr() ustx = UnsignedTransaction().createFromTxOutSelection(selectedUtxoList, scrPairs, pubKeyMap) masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:'))) # Sign and prepare the final transaction for broadcast masterWallet.signUnsignedTx(ustx) pytx = ustx.getPyTxSignedIfPossible() print '\nSigned transaction to be broadcast using Armory "offline transactions"...' print ustx.serializeAscii() finally: TheBDM.beginCleanShutdown() return pytx
def testUnsignedTx(self): ustxi = UnsignedTxInput(tx1raw, 1, None, self.pubKey) a160_1 = addrStr_to_hash160('mhyjJTq9RsDfhNdjTkga1CKhTiL5VFw85J')[1] a160_2 = addrStr_to_hash160('mgoCqfR25kZVApAGFK3Tx5CTNcCppmKwfb')[1] dtxo1 = DecoratedTxOut(hash160_to_p2pkhash_script(a160_1), long(1.00 * ONE_BTC)) dtxo2 = DecoratedTxOut(hash160_to_p2pkhash_script(a160_2), long(0.49 * ONE_BTC)) ustx = UnsignedTransaction().createFromUnsignedTxIO([ustxi], [dtxo1, dtxo2]) self.assertEqual(len(ustx.ustxInputs), 1) self.assertEqual(len(ustx.decorTxOuts), 2) self.assertEqual(ustx.lockTime, 0) self.assertEqual(ustx.uniqueIDB58, 'J2mRenD7') serUstx = ustx.serialize() ustx2 = UnsignedTransaction().unserialize(serUstx) self.assertEqual(serUstx, ustx2.serialize()) serUstxASCII = ustx.serializeAscii() ustx2 = UnsignedTransaction().unserializeAscii(serUstxASCII) self.assertEqual(serUstx, ustx2.serialize())
def testSendmany(self): # Send 1 BTC serializedUnsignedTx = \ self.jsonServer.jsonrpc_createustxformany(None, ','.join([TIAB_WLT_3_ADDR_2, str(BTC_TO_SEND)]), \ ','.join([TIAB_WLT_3_ADDR_3, str(BTC_TO_SEND)])) unsignedTx = UnsignedTransaction().unserializeAscii( serializedUnsignedTx) # Should have 2 txouts to TIAB_WLT_3_ADDR_3 and the change self.assertEqual(len(unsignedTx.decorTxOuts), 3) txOutsFound = 0 for txout in unsignedTx.decorTxOuts: if script_to_addrStr( txout.binScript) in [TIAB_WLT_3_ADDR_2, TIAB_WLT_3_ADDR_3]: self.assertEqual(txout.value, JSONtoAmount(BTC_TO_SEND)) txOutsFound += 1 self.assertEqual(txOutsFound, 2)
def distributeBtc(masterWallet, amount, sendingAddrList): pytx = None setupTheBDM() try: recipValuePairs = [] utxoList = [] for sendingAddr in sendingAddrList: addr160 = sendingAddr.getAddr160() # Make sure the sending addresses are in the masterWallet if not masterWallet.hasAddr(addr160): raise WalletAddressError, 'Address is not in wallet! [%s]' % sendingAddr.getAddrStr() utxoList.extend(masterWallet.getAddrTxOutList(addr160)) for importedAddr in masterWallet.getLinearAddrList(): if importedAddr.chainIndex<0: recipValuePairs.append((importedAddr.getAddr160(),amount)) totalSpend = len(recipValuePairs)*amount fee = calcMinSuggestedFees(utxoList, totalSpend, MIN_RELAY_TX_FEE, len(recipValuePairs))[1] # Get the necessary utxo list selectedUtxoList = PySelectCoins(utxoList, totalSpend, fee) # get total value totalAvailable = sum([u.getValue() for u in selectedUtxoList]) totalChange = totalAvailable - (totalSpend + fee) # Make sure there are funds to cover the transaction. if totalChange < 0: print '***ERROR: you are trying to spend more than your balance!' raise NegativeValueError recipValuePairs.append((masterWallet.getNextUnusedAddress().getAddr160(), totalChange )) # ACR: To support P2SH in general, had to change createFromTxOutSelection # to take full scripts, not just hash160 values. Convert the list # before passing it in scrPairs = [[hash160_to_p2pkhash_script(r), v] for r,v in recipValuePairs] txdp = UnsignedTransaction().createFromTxOutSelection(selectedUtxoList, scrPairs) masterWallet.unlock(securePassphrase = SecureBinaryData(getpass('Enter your secret string:'))) # Sign and prepare the final transaction for broadcast masterWallet.signTxDistProposal(txdp) pytx = txdp.getPyTxSignedIfPossible() print '\nSigned transaction to be broadcast using Armory "offline transactions"...' print txdp.serializeAscii() finally: TheBDM.execCleanShutdown() return pytx
def testAddSigToUSTX(self): ustxi = UnsignedTxInput(tx1raw, 1, None, self.pubKey) a160_1 = addrStr_to_hash160('mhyjJTq9RsDfhNdjTkga1CKhTiL5VFw85J')[1] a160_2 = addrStr_to_hash160('mgoCqfR25kZVApAGFK3Tx5CTNcCppmKwfb')[1] dtxo1 = DecoratedTxOut(hash160_to_p2pkhash_script(a160_1), long(1.00 * ONE_BTC)) dtxo2 = DecoratedTxOut(hash160_to_p2pkhash_script(a160_2), long(0.49 * ONE_BTC)) ustx = UnsignedTransaction().createFromUnsignedTxIO([ustxi], [dtxo1, dtxo2]) msIndex = ustx.insertSignatureForInput(0, self.sigStr, self.pubKey) self.assertEqual(msIndex, 0) msIndex = ustx.insertSignatureForInput(0, self.sigStr) self.assertEqual(msIndex, 0) badSig = self.sigStr[:16] + '\x00' * 8 + self.sigStr[24:] msIndex = ustx.insertSignatureForInput(0, badSig) self.assertEqual(msIndex, -1)
def testCreateMultisigTests(self): ''' This is used solely to generate some multi-sig scripts, using known public/private keys, that we can then use to test signing, etc. This test doesn't actually test anything, but could be tweaked and then reenabled to produce new data for new tests ''' import textwrap asc_nosig = textwrap.dedent(""" =====TXSIGCOLLECT-5JxmLy4T====================================================== AQAAAAsRCQcAAAAAAf19AQEAAAALEQkH/XsoFKgwJMVZsviXpv+aOun4BQHRm+Cuvs/X7O/J3n8BAAAA /QMBAQAAAAGcgxlJ0d+ZHi+MzG+laL4qTx/jVH/lPbbKmrGLA1oc8AAAAACMSTBGAiEArOklwdcihg72 fMu+GvnKF+AdFiMmeT7CWV4KMZmA3kcCIQDyjBMqkI6tFVXMG/yhbBhVg7TNYsAGLjM5UWLfVx57WgFB BLmTMVBhjWo901GrcZzZMNBUectdX4ZsVyHhMNjZpaAJxlpQqnjiK9PAvrNqOIgMq8itz9S3KDaOs/Kh W6/lJNL/////AsAOFgIAAAAAGXapFInbjSGPxqYLm35NTXhzcAkVf8h8iKwwq98DAAAAABl2qRSBj0Gs NlhCyvZkoRO2iRw54544foisAAAAAAAA/////wFBBJ6i78WXHp6ywhTupFpF7A0V2jwQEjE9pWO1+7wZ qS+IM59Dur1Ut5OC+yUycjeFHQdqemkBDFT97zMCJalmtXwAAALiAQAAAAsRCQfJUkEEagSrmNnkd0rY BuMC3d62O+oWtctfIj7ndHjoYbtYPrM2tvvLYLWz1PFVGsReX/xJNkZufZj2x8Dsc2U590aRpkEEaGgH N8dtq7gByyIE9X2+TkV55PcQzWfcG0InWSyB6bXPArWsnotMn0m+UlEFa2ptAR5MN/a20X7ea1X6ojUZ 4kEEuVwknYT0F+PjlaEnQlQotUBnHMFYgeuCjBe3IqU/xZniHKXlbJDzQJiNOTOsx2vrgy/WTKsHjd88 5zKSMDHRqFOuoH+IAgAAAAAAAAROT05FADIBAAAACxEJBxl2qRRs7kd5CHIvdApqfOmMDp1dyrD6Mois gARXAQAAAAAAAAROT05FAA== ================================================================================ """.strip()) asc_sig = textwrap.dedent(""" =====TXSIGCOLLECT-5JxmLy4T====================================================== AQAAAAsRCQcAAAAAAf3EAQEAAAALEQkH/XsoFKgwJMVZsviXpv+aOun4BQHRm+Cuvs/X7O/J3n8BAAAA /QMBAQAAAAGcgxlJ0d+ZHi+MzG+laL4qTx/jVH/lPbbKmrGLA1oc8AAAAACMSTBGAiEArOklwdcihg72 fMu+GvnKF+AdFiMmeT7CWV4KMZmA3kcCIQDyjBMqkI6tFVXMG/yhbBhVg7TNYsAGLjM5UWLfVx57WgFB BLmTMVBhjWo901GrcZzZMNBUectdX4ZsVyHhMNjZpaAJxlpQqnjiK9PAvrNqOIgMq8itz9S3KDaOs/Kh W6/lJNL/////AsAOFgIAAAAAGXapFInbjSGPxqYLm35NTXhzcAkVf8h8iKwwq98DAAAAABl2qRSBj0Gs NlhCyvZkoRO2iRw54544foisAAAAAAAA/////wFBBJ6i78WXHp6ywhTupFpF7A0V2jwQEjE9pWO1+7wZ qS+IM59Dur1Ut5OC+yUycjeFHQdqemkBDFT97zMCJalmtXxHMEQCIF12j4Vj1Shf49BkDWwVzf1kRgYr 4EIPObgRTVPQz2KkAiAQ28gOniv2A5ozeBCk/rpWHTw2DqqkraEUDYLAPr83NQEAAuIBAAAACxEJB8lS QQRqBKuY2eR3StgG4wLd3rY76ha1y18iPud0eOhhu1g+sza2+8tgtbPU8VUaxF5f/Ek2Rm59mPbHwOxz ZTn3RpGmQQRoaAc3x22ruAHLIgT1fb5ORXnk9xDNZ9wbQidZLIHptc8Ctayei0yfSb5SUQVram0BHkw3 9rbRft5rVfqiNRniQQS5XCSdhPQX4+OVoSdCVCi1QGccwViB64KMF7cipT/FmeIcpeVskPNAmI05M6zH a+uDL9ZMqweN3zznMpIwMdGoU66gf4gCAAAAAAAABE5PTkUAMgEAAAALEQkHGXapFGzuR3kIci90Cmp8 6YwOnV3KsPoyiKyABFcBAAAAAAAABE5PTkUA ================================================================================ """.strip()) # For this manual construction to work, I had to save the signed funding # transaction signedFundMS = hex_to_binary( \ '0100000001fd7b2814a83024c559b2f897a6ff9a3ae9f80501d19be0aebecfd7' 'ecefc9de7f010000008a47304402205d768f8563d5285fe3d0640d6c15cdfd64' '46062be0420f39b8114d53d0cf62a4022010dbc80e9e2bf6039a337810a4feba' '561d3c360eaaa4ada1140d82c03ebf37350141049ea2efc5971e9eb2c214eea4' '5a45ec0d15da3c1012313da563b5fbbc19a92f88339f43babd54b79382fb2532' '7237851d076a7a69010c54fdef330225a966b57cffffffff02a07f8802000000' '00c95241046a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e8' '61bb583eb336b6fbcb60b5b3d4f1551ac45e5ffc4936466e7d98f6c7c0ec7365' '39f74691a6410468680737c76dabb801cb2204f57dbe4e4579e4f710cd67dc1b' '4227592c81e9b5cf02b5ac9e8b4c9f49be5251056b6a6d011e4c37f6b6d17ede' '6b55faa23519e24104b95c249d84f417e3e395a127425428b540671cc15881eb' '828c17b722a53fc599e21ca5e56c90f340988d3933acc76beb832fd64cab078d' 'df3ce732923031d1a853ae80045701000000001976a9146cee477908722f740a' '6a7ce98c0e9d5dcab0fa3288ac00000000') #UnsignedTransaction().unserializeAscii(asc_nosig).evaluateSigningStatus().pprint() #UnsignedTransaction().unserializeAscii(asc_sig).evaluateSigningStatus().pprint() privKeys = [SecureBinaryData(a * 32) for a in ['\xaa', '\xbb', '\xcc']] pubKeys = [CryptoECDSA().ComputePublicKey(prv) for prv in privKeys] pubStrs = [pubk.toBinStr() for pubk in pubKeys] for i, prv in enumerate(privKeys): print 'PrivKey %d:', prv.toHexStr() msScript = pubkeylist_to_multisig_script(pubStrs, 2) msScriptReverse = pubkeylist_to_multisig_script(pubStrs[::-1], 2) self.assertEqual(msScript, msScriptReverse) for opStr in convertScriptToOpStrings(msScript): print ' ', opStr dtxo = DecoratedTxOut(msScript, 1.0 * ONE_BTC) ustxi = UnsignedTxInput(signedFundMS, 0) ustxi.pprint() refund1 = addrStr_to_scrAddr('mqSvihZRtKt1J3EBbwBJSHeAYVjdxUnpvf') refund2 = addrStr_to_scrAddr('mjAauu6jzmYaE7jrfFgKqLxtvpStmPxcb7') dtxo1 = DecoratedTxOut(scrAddr_to_script(refund1), long(0.223 * ONE_BTC)) dtxo2 = DecoratedTxOut(scrAddr_to_script(refund2), long(0.200 * ONE_BTC)) ustx = UnsignedTransaction().createFromUnsignedTxIO([ustxi], [dtxo1, dtxo2]) ustx.pprint() ustx.evaluateSigningStatus().pprint() # Need a candidate tx to test signing txObj = ustx.pytxObj # Test signing on the individual USTXI NOSIG = TXIN_SIGSTAT.NO_SIGNATURE SIG = TXIN_SIGSTAT.ALREADY_SIGNED for i in [0, 1]: for j in [0, 1]: for k in [0, 1]: ustxiCopy = UnsignedTxInput().unserialize( ustxi.serialize()) if i > 0: ustxiCopy.createAndInsertSignature(txObj, privKeys[0]) if j > 0: ustxiCopy.createAndInsertSignature(txObj, privKeys[1]) if k > 0: ustxiCopy.createAndInsertSignature(txObj, privKeys[2]) sstat = ustxiCopy.evaluateSigningStatus() sstat.pprint() self.assertEqual(sstat.allSigned, (i + j + k) > 1) self.assertEqual(sstat.statusM[0], NOSIG if i + j + k == 0 else SIG) self.assertEqual(sstat.statusM[1], NOSIG if i + j + k < 2 else SIG) # Now try all this on the full USTX (not just the input for i in [0, 1]: for j in [0, 1]: for k in [0, 1]: ustxCopy = UnsignedTransaction().unserialize( ustx.serialize()) if i > 0: ustxCopy.createAndInsertSignatureForInput( 0, privKeys[0]) if j > 0: ustxCopy.createAndInsertSignatureForInput( 0, privKeys[1]) if k > 0: ustxCopy.createAndInsertSignatureForInput( 0, privKeys[2]) sstat = ustxCopy.evaluateSigningStatus() #sstat.pprint() self.assertEqual(sstat.canBroadcast, (i + j + k) > 1) #self.assertEqual(sstat.statusM[0], NOSIG if i+j+k==0 else SIG) #self.assertEqual(sstat.statusM[1], NOSIG if i+j+k<2 else SIG) # Now actually sign it and dump out a raw signed tx! ustx.createAndInsertSignatureForInput(0, privKeys[0]) ustx.createAndInsertSignatureForInput(0, privKeys[2]) print ustx.serializeAscii() print binary_to_hex(ustx.getPyTxSignedIfPossible().serialize())