Bitcoin Forum
April 18, 2024, 07:17:33 AM *
News: Latest Bitcoin Core release: 26.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: CLI tx signing  (Read 1364 times)
Snowman23 (OP)
Newbie
*
Offline Offline

Activity: 8
Merit: 0


View Profile
September 23, 2014, 11:25:14 PM
 #1

Good day everyone!

First off, this is my first post so hi! Cheesy

I hope someone can help me, I am seriously stuck. I am basically trying to create a script getting Armory to sign transactions offline. I tried searching the forums, but can't seem to find anything since Armory got updated.

cli_sign_txdp.py in the extras folder is outdated and while I did manage to get somewhere with it, I didn't get very far. I found PromoKit.py slightly more helpful but am still stumped.

I have some programming knowledge behind me, but this is the first time I've used Python. I don't need to connect to the blockchain or anything to do with networking, just basically get cli_sign_txdp.py working - run the for loop to make sure all input addresses are in the wallet, display inputs and outputs, ask for passphrase then create the signed tx.

At this point I'm stuck on the for loop with the error "TypeError: 'PyBtcAddress' object does not support indexing" and I have no idea if I'm even on the right track. Any help, even a nudge in the right direction, would be greatly appreciated!

Thanks!
1713424653
Hero Member
*
Offline Offline

Posts: 1713424653

View Profile Personal Message (Offline)

Ignore
1713424653
Reply with quote  #2

1713424653
Report to moderator
1713424653
Hero Member
*
Offline Offline

Posts: 1713424653

View Profile Personal Message (Offline)

Ignore
1713424653
Reply with quote  #2

1713424653
Report to moderator
1713424653
Hero Member
*
Offline Offline

Posts: 1713424653

View Profile Personal Message (Offline)

Ignore
1713424653
Reply with quote  #2

1713424653
Report to moderator
The forum was founded in 2009 by Satoshi and Sirius. It replaced a SourceForge forum.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1713424653
Hero Member
*
Offline Offline

Posts: 1713424653

View Profile Personal Message (Offline)

Ignore
1713424653
Reply with quote  #2

1713424653
Report to moderator
1713424653
Hero Member
*
Offline Offline

Posts: 1713424653

View Profile Personal Message (Offline)

Ignore
1713424653
Reply with quote  #2

1713424653
Report to moderator
1713424653
Hero Member
*
Offline Offline

Posts: 1713424653

View Profile Personal Message (Offline)

Ignore
1713424653
Reply with quote  #2

1713424653
Report to moderator
etotheipi
Legendary
*
Offline Offline

Activity: 1428
Merit: 1093


Core Armory Developer


View Profile WWW
September 24, 2014, 02:07:01 AM
 #2

Good day everyone!

First off, this is my first post so hi! Cheesy

I hope someone can help me, I am seriously stuck. I am basically trying to create a script getting Armory to sign transactions offline. I tried searching the forums, but can't seem to find anything since Armory got updated.

cli_sign_txdp.py in the extras folder is outdated and while I did manage to get somewhere with it, I didn't get very far. I found PromoKit.py slightly more helpful but am still stumped.

I have some programming knowledge behind me, but this is the first time I've used Python. I don't need to connect to the blockchain or anything to do with networking, just basically get cli_sign_txdp.py working - run the for loop to make sure all input addresses are in the wallet, display inputs and outputs, ask for passphrase then create the signed tx.

At this point I'm stuck on the for loop with the error "TypeError: 'PyBtcAddress' object does not support indexing" and I have no idea if I'm even on the right track. Any help, even a nudge in the right direction, would be greatly appreciated!

Thanks!

Don't have much time to respond at the moment, but check the "dev" branch.  I believe CircusPeanut recently updated a bunch of those scripts (rather, I asked him to, and I know he started but I don't know if he finished). 

Btw, welcome to the forums!

Founder and CEO of Armory Technologies, Inc.
Armory Bitcoin Wallet: Bringing cold storage to the average user!
Only use Armory software signed by the Armory Offline Signing Key (0x98832223)

Please donate to the Armory project by clicking here!    (or donate directly via 1QBDLYTDFHHZAABYSKGKPWKLSXZWCCJQBX -- yes, it's a real address!)
Snowman23 (OP)
Newbie
*
Offline Offline

Activity: 8
Merit: 0


View Profile
September 24, 2014, 09:26:02 AM
 #3

Don't have much time to respond at the moment, but check the "dev" branch.  I believe CircusPeanut recently updated a bunch of those scripts (rather, I asked him to, and I know he started but I don't know if he finished). 

Btw, welcome to the forums!

That's great! Thanks and thank you so much for Armory!
Snowman23 (OP)
Newbie
*
Offline Offline

Activity: 8
Merit: 0


View Profile
September 24, 2014, 11:43:36 AM
Last edit: September 24, 2014, 02:37:41 PM by Snowman23
 #4

Just in case anyone is interested, I got it working.

I removed some of the validation code that lists all addresses (I think it does that) and I removed an error checking function called checkTxHasEnoughSignatures. Basically I took them out because I don't need them and I just wanted to get the script working for now without manually removing all my hair Tongue.

But anyway, here is a working (tested with testnet coins) update of cli_sign_txdp.py, I hope someone finds it useful. Please forgive me if the formatting or spacing or whatever is wrong, I have never had code leave my computer and have never played with Python until I started this last night.

Code:
#! /usr/bin/python
import sys
sys.path.append('..')
sys.path.append('.')

from armoryengine.ALL import *
import getpass
from sys import argv
import os

# Do not ever access the same wallet file from two different processes at the same time
print '\n'
raw_input('PLEASE CLOSE ARMORY BEFORE RUNNING THIS SCRIPT!  (press enter to continue)\n')

if len(argv)<3:
   print 'USAGE: %s <wallet file> <unsigned.tx file>' % argv[0]
   exit(0)

wltfile  = argv[1]
txdpfile = argv[2]

#masterWallet = PyBtcWallet().readWalletFile(wltfile, False, False)

if not os.path.exists(wltfile):
   print 'Wallet file was not found: %s' % wltfile

if not os.path.exists(txdpfile):
   print 'Transaction file was not found: %s' % txdpfile

wlt  = PyBtcWallet().readWalletFile(wltfile)
txdp = UnsignedTransaction().unserializeAscii( open(txdpfile,'r').read())

for a160 in wlt.getAddrList():
   if not wlt.hasAddr(a160):
      print 'ERROR: Not all transaction inputs can be signed by this wallet!'
      print '       Did you supply the correct wallet?'
      exit(0)

print '********************************************************************************'
print 'PLEASE VERIFY THE TRANSACTION DETAILS BEFORE SIGNING'
print '********************************************************************************'


btcIn = sum([u.value for u in txdp.ustxInputs])
btcOut = sum([o.value for o in txdp.pytxObj.outputs])
btcFee = btcIn - btcOut

print 'Input: ', btcIn
print 'Output: ', btcOut
print 'Fee: ', btcFee

confirm = raw_input('\nDoes this look right?  [y/N]: ')
if not confirm.lower().startswith('y'):
   print 'User did not approve of the transaction.  Aborting.'
   exit(0)
  

# If the wallet is encrypted, get the passphrase
if wlt.useEncryption:
   print 'Please enter your passphrase to unlock your wallet: '
   for ntries in range(3):
      passwd = SecureBinaryData(getpass.getpass('Wallet Passphrase: '))
      if wlt.verifyPassphrase(passwd):
         break;

      print 'Passphrase was incorrect!'
      if ntries==2:
         print 'Wallet could not be unlocked.  Aborting.'
         exit(0)

   print 'Correct Passphrase.  Unlocking wallet...'
   wlt.unlock(securePassphrase=passwd)
   passwd.destroy()
  

try:
   wlt.signUnsignedTx(txdp)
except WalletLockError:
   print 'Error signing transaction.  Wallet is somehow still locked'
   raise
except:
   print 'Error signing transaction.  Unknown reason.'
   raise

if not txdp.verifyInputsMatchPyTxObj():
   print 'Error signing transaction.  Most likely this is not the correct wallet.'
   exit(0)


outfilename = '.'.join(txdpfile.split('.')[:-2] + ['signed.tx'] )
outfile = open(outfilename, 'w')
outfile.write(txdp.serializeAscii())
outfile.close()
print '\nSigning was successful!  The signed transaction is located:'
print '\t', outfilename, '\n'
doDelete = raw_input('Would you like to delete the old unsigned transaction? [Y/n]: ')
if not doDelete.lower().startswith('n'):
   os.remove(txdpfile)

print ''
print 'The *.signed.tx file can now be broadcast from any computer running '
print 'Armory in online mode.  Click "Offline Transactions" and "Broadcast".'
print ''

I TAKE ZERO CREDIT!!! If you want to thank anyone, donate some BTC to 1ArmoryXcfq7TnCSuZa9fQjRYwJ4bkRKfv

EDIT - changed first for loop. Added hash check function (I think)
etotheipi
Legendary
*
Offline Offline

Activity: 1428
Merit: 1093


Core Armory Developer


View Profile WWW
September 24, 2014, 02:24:41 PM
 #5

Fantastic.  Did you end up using the dev branch?

There was a few major architectural changes between when that script was written and the latest version.  Mainly, the whole offline interface changed and uses "UnsignedTransaction" objects now instead of "PyTxDistProposal" objects (PyTxDP).  This was done to accommodate multi-sig, and now offline transactions are treated as a 1-of-1 multisig transaction.  Even though the GUI makes them look different, they actually both use identical code and serializations since 0.92.

Founder and CEO of Armory Technologies, Inc.
Armory Bitcoin Wallet: Bringing cold storage to the average user!
Only use Armory software signed by the Armory Offline Signing Key (0x98832223)

Please donate to the Armory project by clicking here!    (or donate directly via 1QBDLYTDFHHZAABYSKGKPWKLSXZWCCJQBX -- yes, it's a real address!)
Snowman23 (OP)
Newbie
*
Offline Offline

Activity: 8
Merit: 0


View Profile
September 24, 2014, 02:52:59 PM
 #6

Fantastic.  Did you end up using the dev branch?

There was a few major architectural changes between when that script was written and the latest version.  Mainly, the whole offline interface changed and uses "UnsignedTransaction" objects now instead of "PyTxDistProposal" objects (PyTxDP).  This was done to accommodate multi-sig, and now offline transactions are treated as a 1-of-1 multisig transaction.  Even though the GUI makes them look different, they actually both use identical code and serializations since 0.92.

Actually I didn't use the dev branch. I took a look at the extras folder in it and decided it would be easier to learn some Python basics quickly. Then pretty much tore through Transaction.py and PyBtcWallet.py and just found code doing what I thought the script was trying to do.

I realized all transactions were treated as multi-sig which makes sense and will come in handy when I move on from signing. The change in the code doesn't affect me too much since I never looked into the code of previous Armory versions, just used the GUI. I've actually had a lot of fun rooting through your code! I haven't touched programming in a couple years until I got an idea using Armory and that just forced me to use every minute of my free time on this Cheesy

If I find any other scripts that aren't working, I'll try fix them up. I'm using a very stripped down version of this script which eliminates all user input as a snippet in a bigger program, but I just want to document the full version in case someone else is looking for it
Snowman23 (OP)
Newbie
*
Offline Offline

Activity: 8
Merit: 0


View Profile
September 24, 2014, 08:32:05 PM
Last edit: September 26, 2014, 07:38:55 AM by Snowman23
 #7

Stripped down automatic script (just add args) in case anyone finds it useful. Remove password code if not needed. In, out and fee totals are created but not used in case they're needed


WARNING!!! Please read the warning by etotheipi below! tl;dr - this script is not intended to be used as it, it makes Armory pretty much worthless if it just signs anything. The sole purpose of this script is for research and understanding of how the Armory signing process works. If you use the script as is, you may as well get an Android and use a wallet app that stores your keys in cleartext. This post is under "Development & Technical Discussion" for a reason. Stay safe!

Code:
#! /usr/bin/python
import sys
sys.path.append('..')
sys.path.append('.')

from armoryengine.ALL import *
import getpass
from sys import argv
import os

wltfile  = argv[1]
txdpfile = argv[2]

wlt  = PyBtcWallet().readWalletFile(wltfile)
txdp = UnsignedTransaction().unserializeAscii( open(txdpfile,'r').read())

btcIn = sum([i.value for i in txdp.ustxInputs])
btcOut = sum([o.value for o in txdp.decorTxOuts])
btcFee = btcIn - btcOut

passwd = SecureBinaryData('Password')
wlt.unlock(securePassphrase=passwd)
passwd.destroy()

wlt.signUnsignedTx(txdp)
outfilename = '.'.join(txdpfile.split('.')[:-2] + ['signed.tx'] )
outfile = open(outfilename, 'w')
outfile.write(txdp.serializeAscii())
outfile.close()
etotheipi
Legendary
*
Offline Offline

Activity: 1428
Merit: 1093


Core Armory Developer


View Profile WWW
September 24, 2014, 09:46:59 PM
 #8

Please note:  while I understand you were simply trying to get stuff to work, I encourage you to get the verification dialog back into the script.  Offline signing has a dramatically reduced security profile if you are not manually verifying the transaction details in the secure environment. 

For instance, your online computer is compromised.  You request a transaction to send 1 BTC to address A.  The online computer tells you that's what the transaction is for, but the transaction it saves to the USB is for 100 BTC from your wallet to address B (owned by the attacker).   If you blindly sign it, you won't know what happened until it's too late.

This is why the Trezor has a little screen on it to display tx details and have you submit a physical button press.  It assumes the transaction came from an untrusted environment and needs to be reviewed in the trusted environment.

Less critical, but still important... I recommend you not hardcode your password into the script.  The password on your wallet isn't very useful if there's a plaintext file (the script) sitting on your harddrive with the password.  The "getpass" module in the original script allows the terminal to collect your password at signing time and apply it without touching the disk.

Perhaps your use case is wildly different than I am imagining.  Maybe you are implementing something that needs to do automatic signing and is protected in other ways, such as a firewalled signing device with an address whitelist with rate-limiting, etc.  Just making sure you aware of the various risks associated with removing functionality from the original script.

Founder and CEO of Armory Technologies, Inc.
Armory Bitcoin Wallet: Bringing cold storage to the average user!
Only use Armory software signed by the Armory Offline Signing Key (0x98832223)

Please donate to the Armory project by clicking here!    (or donate directly via 1QBDLYTDFHHZAABYSKGKPWKLSXZWCCJQBX -- yes, it's a real address!)
Snowman23 (OP)
Newbie
*
Offline Offline

Activity: 8
Merit: 0


View Profile
September 25, 2014, 06:13:30 AM
 #9

Please note:  while I understand you were simply trying to get stuff to work, I encourage you to get the verification dialog back into the script.  Offline signing has a dramatically reduced security profile if you are not manually verifying the transaction details in the secure environment. 

For instance, your online computer is compromised.  You request a transaction to send 1 BTC to address A.  The online computer tells you that's what the transaction is for, but the transaction it saves to the USB is for 100 BTC from your wallet to address B (owned by the attacker).   If you blindly sign it, you won't know what happened until it's too late.

This is why the Trezor has a little screen on it to display tx details and have you submit a physical button press.  It assumes the transaction came from an untrusted environment and needs to be reviewed in the trusted environment.

Less critical, but still important... I recommend you not hardcode your password into the script.  The password on your wallet isn't very useful if there's a plaintext file (the script) sitting on your harddrive with the password.  The "getpass" module in the original script allows the terminal to collect your password at signing time and apply it without touching the disk.

Perhaps your use case is wildly different than I am imagining.  Maybe you are implementing something that needs to do automatic signing and is protected in other ways, such as a firewalled signing device with an address whitelist with rate-limiting, etc.  Just making sure you aware of the various risks associated with removing functionality from the original script.


Thank you for your concern. It is completely understandable and I understand the risks.

However I am not using the script in that way at all. The purpose of providing the raw script was so the bare functionality could be seen and worked upon afterwards. I left the functions such as amount calculations and passwords in so that it would be easily seen how to validate transactions if needed. When I have some more time, I will add the last part of the script that is missing too.

All I thought I would do was add what I was looking for in the first place. I know most want to just use the default script which is why it's there and I'm trying to add parts I won't even use, but there are (be it very few probably) some people who would like to use parts of the scripts for other purposes. Armory is extremely complex with a lot of code, I just thought it would be simpler for someone.

If you would feel more comfortable I removed the stripped down script, I would be more than happy too, please just let me know Smiley
etotheipi
Legendary
*
Offline Offline

Activity: 1428
Merit: 1093


Core Armory Developer


View Profile WWW
September 25, 2014, 03:20:36 PM
 #10

No need to remove stuff.  Just make sure appropriate warnings are in place.   I just wanted you to be aware of the risks associated with the changes you made, as it's easy to get impatient and be happy with anything that works Smiley

We're going to be making sure all those things in the extras directory are updated.  You're just a little bit too early to the party.

Founder and CEO of Armory Technologies, Inc.
Armory Bitcoin Wallet: Bringing cold storage to the average user!
Only use Armory software signed by the Armory Offline Signing Key (0x98832223)

Please donate to the Armory project by clicking here!    (or donate directly via 1QBDLYTDFHHZAABYSKGKPWKLSXZWCCJQBX -- yes, it's a real address!)
Snowman23 (OP)
Newbie
*
Offline Offline

Activity: 8
Merit: 0


View Profile
September 26, 2014, 07:39:09 AM
 #11

No need to remove stuff.  Just make sure appropriate warnings are in place.   I just wanted you to be aware of the risks associated with the changes you made, as it's easy to get impatient and be happy with anything that works Smiley

We're going to be making sure all those things in the extras directory are updated.  You're just a little bit too early to the party.

I have added a warning to the code just in case someone does use as is Tongue

The more I dig into Armory, the more I appreciate it. If I have to figure out how one tiny script works compared to Armory itself, it doesn't bother me. I just wanted to see if anyone knew and help anyone who wants to know Smiley
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!