From 576d8036c798249e237c422dad5a1e94a4082a21 Mon Sep 17 00:00:00 2001 From: philemon Date: Mon, 31 Jul 2017 20:10:17 +0300 Subject: [PATCH] Support for the Aug 1 2017 UAHF ("Bitcoin Cash", "Bitcoin ABC") Brief instructions for Linux (Windows users may adapt to fit): Make a copy of your Bitcoin data directory, including the blockchain and your tracking wallet (the blockchain must have been synced last BEFORE 12:20 UTC Aug. 1). This can be done as follows: $ mkdir ~/.bitcoin-abc $ rsync -av ~/.bitcoin/* ~/.bitcoin-abc If you messed up and synced your blockchain AFTER the HF, then do the following, after which you'll have to sync the ABC chain from scratch: $ mkdir ~/.bitcoin-abc $ cp ~/.bitcoin/{bitcoin.conf,*wallet*.dat} ~/.bitcoin-abc Download the Bitcoin ABC binary, but DON'T let it install automatically. Or alternatively, clone the source from Github and compile it yourself: Binary: https://download.bitcoinabc.org/0.14.6 Source: git clone https://github.com/Bitcoin-ABC/bitcoin-abc Install the Bitcoin ABC daemon BY HAND into your exec path as 'bitcoind-abc': $ sudo cp bitcoind /usr/local/bin/bitcoind-abc Start the daemon and let it sync the ABC chain: $ bitcoind-abc -datadir=$HOME/.bitcoin-abc -daemon Don't forget to always start the ABC daemon with the -datadir argument. Otherwise you could trash your Core blockchain! Once the HF has activated, you sign or create-sign-send transactions on the ABC chain by invoking 'mmgen-txsign' or 'mmgen-txdo' with the --aug1hf switch. All other commands, including 'mmgen-txcreate' and 'mmgen-txsend', are invoked as usual, with no additional command-line switches. Your address balances and unspent outputs will display correctly for whatever chain you're on at the moment. To switch back to the Core chain, just stop the ABC daemon and restart the Core daemon (WITHOUT the -datadir argument). After the Aug. 1 HF, Core transactions and ABC transactions will be incompatible, as they use an incompatible sighash type. This prevents transactions from being broadcast (and hence replayed) on the wrong chain. So if you use the --aug1hf switch on the Core chain, or forget to use it on the ABC chain, nothing bad will happen; your sign or send operation will just fail with an error message. The main danger is forgetting which daemon is running at the moment and therefore which chain you're on. This can be checked on Linux with the command `pgrep -a bitcoind` or on Windows by examining the task manager. In case you were wondering, all the --aug1hf switch does is perform a few sanity checks and call signrawtransaction with 'ALL|FORKID' as the 'sighashtype' argument. There's nothing more to it than that! --- mmgen/globalvars.py | 3 +- mmgen/main_txbump.py | 2 +- mmgen/main_txdo.py | 1 + mmgen/main_txsign.py | 1 + mmgen/tx.py | 66 ++++++++++++++++++++++++++++++-------------- mmgen/txsign.py | 2 +- 6 files changed, 51 insertions(+), 24 deletions(-) diff --git a/mmgen/globalvars.py b/mmgen/globalvars.py index 8b09645c..d31d8b4d 100755 --- a/mmgen/globalvars.py +++ b/mmgen/globalvars.py @@ -38,7 +38,7 @@ class g(object): sys.exit(ev) # Variables - these might be altered at runtime: - version = '0.9.2' + version = '0.9.299' release_date = 'July 2017' proj_name = 'MMGen' @@ -115,6 +115,7 @@ class g(object): ('label','keep_label'), ('tx_id','info'), ('tx_id','terse_info'), + ('aug1hf','rbf'), ('batch','rescan') ) cfg_file_opts = ( diff --git a/mmgen/main_txbump.py b/mmgen/main_txbump.py index 35ba6f21..6c652345 100755 --- a/mmgen/main_txbump.py +++ b/mmgen/main_txbump.py @@ -71,7 +71,7 @@ opts_data = { 'notes': '\n' + fee_notes + txsign_notes } -cmd_args = opts.init(opts_data) +cmd_args = opts.init(opts_data,add_opts=['aug1hf']) c = bitcoin_connection() diff --git a/mmgen/main_txdo.py b/mmgen/main_txdo.py index c86bf9d8..6864958d 100755 --- a/mmgen/main_txdo.py +++ b/mmgen/main_txdo.py @@ -30,6 +30,7 @@ opts_data = { 'options': """ -h, --help Print this help message --, --longhelp Print help message for long options (common options) +-A, --aug1hf Sign transaction for the Aug. 1 2017 UAHF chain -a, --tx-fee-adj= f Adjust transaction fee by factor 'f' (see below) -b, --brain-params=l,p Use seed length 'l' and hash preset 'p' for brainwallet input diff --git a/mmgen/main_txsign.py b/mmgen/main_txsign.py index 1d330518..c418d308 100755 --- a/mmgen/main_txsign.py +++ b/mmgen/main_txsign.py @@ -30,6 +30,7 @@ opts_data = { 'options': """ -h, --help Print this help message --, --longhelp Print help message for long options (common options) +-A, --aug1hf Sign transaction for the Aug. 1 2017 UAHF chain -b, --brain-params=l,p Use seed length 'l' and hash preset 'p' for brainwallet input -d, --outdir= d Specify an alternate directory 'd' for output diff --git a/mmgen/tx.py b/mmgen/tx.py index a943b340..a30e8d9d 100755 --- a/mmgen/tx.py +++ b/mmgen/tx.py @@ -441,6 +441,9 @@ class MMGenTX(MMGenObject): self.die_if_incorrect_chain() + if opt.aug1hf and self.has_segwit_inputs(): + die(2,yellow("'--aug1hf' option is incompatible with Segwit transaction inputs!")) + if not keys: msg('No keys. Cannot sign!') return False @@ -462,23 +465,34 @@ class MMGenTX(MMGenObject): from mmgen.bitcoin import hash256 msg_r('Signing transaction{}...'.format(tx_num_str)) - # sighashtype defaults to 'ALL' - sig_tx = c.signrawtransaction(self.hex,sig_data,keys.values()) + ht = ('ALL','ALL|FORKID')[bool(opt.aug1hf)] # sighashtype defaults to 'ALL' + ret = c.signrawtransaction(self.hex,sig_data,keys.values(),ht,on_fail='return') - if sig_tx['complete']: - self.hex = sig_tx['hex'] - vmsg('Signed transaction size: {}'.format(len(self.hex)/2)) - dt = DeserializedTX(self.hex) - txid = dt['txid'] - self.check_sigs(dt) - assert txid == c.decoderawtransaction(self.hex)['txid'], 'txid mismatch (after signing)' - self.btc_txid = BitcoinTxID(txid,on_fail='return') - msg('OK') - return True - else: - msg('failed\nBitcoind returned the following errors:') - msg(repr(sig_tx['errors'])) + from mmgen.rpc import rpc_error,rpc_errmsg + if rpc_error(ret): + errmsg = rpc_errmsg(ret) + if 'Invalid sighash param' in errmsg: + m = 'This chain does not support the Aug. 1 2017 UAHF.' + m += "\nRe-run 'mmgen-txsign' or 'mmgen-txdo' without the --aug1hf option." + else: + m = errmsg + msg(yellow(m)) return False + else: + if ret['complete']: + self.hex = ret['hex'] + vmsg('Signed transaction size: {}'.format(len(self.hex)/2)) + dt = DeserializedTX(self.hex) + txid = dt['txid'] + self.check_sigs(dt) + assert txid == c.decoderawtransaction(self.hex)['txid'], 'txid mismatch (after signing)' + self.btc_txid = BitcoinTxID(txid,on_fail='return') + msg('OK') + return True + else: + msg('failed\nBitcoind returned the following errors:') + msg(repr(ret['errors'])) + return False def mark_raw(self): self.desc = 'transaction' @@ -567,10 +581,24 @@ class MMGenTX(MMGenObject): ret = 'deadbeef' * 8 m = 'BOGUS transaction NOT sent: %s' else: - ret = c.sendrawtransaction(self.hex) # exits on failure + ret = c.sendrawtransaction(self.hex,on_fail='return') m = 'Transaction sent: %s' - if ret: + from mmgen.rpc import rpc_error,rpc_errmsg + if rpc_error(ret): + errmsg = rpc_errmsg(ret) + if 'Signature must use SIGHASH_FORKID' in errmsg: + m = 'The Aug. 1 2017 UAHF has activated on this chain.' + m += "\nRe-run 'mmgen-txsign' or 'mmgen-txdo' with the --aug1hf option." + elif 'Illegal use of SIGHASH_FORKID' in errmsg: + m = 'The Aug. 1 2017 UAHF is not yet active on this chain.' + m += "\nRe-run 'mmgen-txsign' or 'mmgen-txdo' without the --aug1hf option." + else: + m = errmsg + msg(yellow(m)) + msg(red('Send of MMGen transaction {} failed'.format(self.txid))) + return False + else: if not bogus_send: assert ret == self.btc_txid, 'txid mismatch (after sending)' self.desc = 'sent transaction' @@ -579,10 +607,6 @@ class MMGenTX(MMGenObject): self.add_blockcount(c) return True - # rpc call exits on failure, so we won't get here - msg('Sending of transaction {} failed'.format(self.txid)) - return False - def write_txid_to_file(self,ask_write=False,ask_write_default_yes=True): fn = '%s[%s].%s' % (self.txid,self.send_amt,self.txid_ext) write_data_to_file(fn,self.btc_txid+'\n','transaction ID', diff --git a/mmgen/txsign.py b/mmgen/txsign.py index 4e8bd5d1..9166dd3c 100755 --- a/mmgen/txsign.py +++ b/mmgen/txsign.py @@ -185,4 +185,4 @@ def txsign(opt,c,tx,seed_files,kl,kal,tx_num_str=''): if tx.sign(c,tx_num_str,dict(keys)): return tx else: - die(3,'failed\nSome keys were missing. Transaction {}could not be signed.'.format(tx_num_str)) + die(3,red('Transaction {}could not be signed.'.format(tx_num_str)))