From b0a553f118d5155e4fd2b95f75177e8a30c82f25 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Thu, 2 Nov 2017 11:40:35 -0400 Subject: [PATCH] add some misc helpful utilities --- bin/cat-json | 11 +++++ bin/cat-jwt | 36 +++++++++++++++ bin/decode-tx | 8 ++++ bin/decode-tx-script | 6 +++ bin/decode-tx-witness-script | 7 +++ bin/send_transaction.py | 88 ++++++++++++++++++++++++++++++++++++ bin/tx-hash | 6 +++ bin/validateProof.js | 53 ++++++++++++++++++++++ 8 files changed, 215 insertions(+) create mode 100755 bin/cat-json create mode 100755 bin/cat-jwt create mode 100755 bin/decode-tx create mode 100755 bin/decode-tx-script create mode 100755 bin/decode-tx-witness-script create mode 100755 bin/send_transaction.py create mode 100755 bin/tx-hash create mode 100755 bin/validateProof.js diff --git a/bin/cat-json b/bin/cat-json new file mode 100755 index 0000000..068965c --- /dev/null +++ b/bin/cat-json @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +import json +import sys + +for path in sys.argv[1:]: + with open(path, 'r') as f: + data = f.read() + print json.dumps( json.loads(data), indent=4, sort_keys=True ) + +sys.exit(0) diff --git a/bin/cat-jwt b/bin/cat-jwt new file mode 100755 index 0000000..f04e1fc --- /dev/null +++ b/bin/cat-jwt @@ -0,0 +1,36 @@ +#!/usr/bin/python + +import jsontokens +import sys +import json +import os + +path = sys.argv[1] +pubkey = None + +if len(sys.argv) > 2: + pubkey = sys.argv[2] + +jwt_str = None +if not os.path.exists(path): + jwt_str = path + +else: + with open(path, "r") as f: + jwt_str = f.read().strip() + +try: + jwt = json.loads(jwt_str) +except: + jwt = [{'token': jwt_str}] + +if pubkey: + v = jsontokens.TokenVerifier() + res = v.verify(jwt[0]['token'], pubkey) + if not res: + print "unverifiable" + sys.exit(1) + +res = jsontokens.decode_token(jwt[0]['token']) +print json.dumps(res, indent=4, sort_keys=True) + diff --git a/bin/decode-tx b/bin/decode-tx new file mode 100755 index 0000000..820849f --- /dev/null +++ b/bin/decode-tx @@ -0,0 +1,8 @@ +#!/usr/bin/env python2 + +import virtualchain +import sys +import json + +tx_str = sys.argv[1] +print json.dumps( virtualchain.btc_tx_deserialize(tx_str), indent=4, sort_keys=True ) diff --git a/bin/decode-tx-script b/bin/decode-tx-script new file mode 100755 index 0000000..ca49580 --- /dev/null +++ b/bin/decode-tx-script @@ -0,0 +1,6 @@ +#!/usr/bin/python2 + +import sys +import bitcoin + +print bitcoin.deserialize_script(sys.argv[1]) diff --git a/bin/decode-tx-witness-script b/bin/decode-tx-witness-script new file mode 100755 index 0000000..b29a25e --- /dev/null +++ b/bin/decode-tx-witness-script @@ -0,0 +1,7 @@ +#!/usr/bin/python2 + +import sys +import virtualchain +import binascii + +print virtualchain.lib.encoding.json_changebase(virtualchain.btc_witness_script_deserialize(sys.argv[1]), lambda x: binascii.hexlify(x)) diff --git a/bin/send_transaction.py b/bin/send_transaction.py new file mode 100755 index 0000000..77ab0d5 --- /dev/null +++ b/bin/send_transaction.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python2 + +import blockstack_client +import virtualchain +import keylib +import sys +import traceback +import pybitcoin +import json + +amount = None + +try: + privkey = sys.argv[1] + recipient_addr = sys.argv[2] + + if len(sys.argv) > 3: + amount = int(sys.argv[3]) + +except Exception as e: + traceback.print_exc() + print >> sys.stderr, "Usage: {} privkey recipient_addr [amount]".format(sys.argv[0]) + sys.exit(1) + +pubkey = keylib.ECPrivateKey(privkey, compressed=False).public_key().to_hex() +payment_addr = keylib.ECPublicKey(pubkey).address() + +utxos = blockstack_client.get_utxos(payment_addr) +if len(utxos) == 0: + print >> sys.stderr, "No UTXOS for {} ({})".format(payment_addr, pubkey) + sys.exit(1) + + +def mktx(satoshis, fee): + + outputs = None + if satoshis is None: + # send all + satoshis = sum([u['value'] for u in utxos]) + + print 'WARN: sending all of {} ({}) to {}'.format(payment_addr, satoshis, recipient_addr) + + outputs = [ + {'script': virtualchain.make_payment_script(payment_addr), + 'value': virtualchain.calculate_change_amount(utxos, 0, fee)}, + ] + + else: + outputs = [ + {"script": virtualchain.make_payment_script(payment_addr), + "value": satoshis}, + + {"script": virtualchain.make_payment_script(recipient_addr), + "value": virtualchain.calculate_change_amount(utxos, satoshis, fee)}, + ] + + txobj = { + 'ins': utxos, + 'outs': outputs, + 'locktime': 0, + 'version': 1 + } + + # log.debug("serialize tx: {}".format(json.dumps(txobj, indent=4, sort_keys=True))) + txstr = virtualchain.btc_tx_serialize(txobj) + signed_txstr = virtualchain.tx_sign_all_unsigned_inputs(privkey, utxos, txstr) + return signed_txstr + +signed_tx = mktx(amount, 0) +tx_fee = virtualchain.get_tx_fee(signed_tx, config_path=blockstack_client.CONFIG_PATH) +assert tx_fee + +signed_tx = mktx(amount, tx_fee) + +print 'tx_fee: {}'.format(tx_fee) +print "tx:" +print signed_tx +print "" +print json.dumps( virtualchain.btc_tx_deserialize(signed_tx), indent=4, sort_keys=True ) + +send = raw_input("Send? (Y/n): ") +if send != 'Y': + sys.exit(0) + +else: + res = blockstack_client.broadcast_tx(signed_tx) + print json.dumps(res, indent=4, sort_keys=True) + diff --git a/bin/tx-hash b/bin/tx-hash new file mode 100755 index 0000000..68f9480 --- /dev/null +++ b/bin/tx-hash @@ -0,0 +1,6 @@ +#!/usr/bin/env python2 + +import bitcoin +import sys + +print bitcoin.txhash(sys.argv[1]) diff --git a/bin/validateProof.js b/bin/validateProof.js new file mode 100755 index 0000000..56c94b0 --- /dev/null +++ b/bin/validateProof.js @@ -0,0 +1,53 @@ +#!/usr/bin/node + +var b = require('blockstack'); +var assert = require('assert'); + +var args = process.argv.slice(2); + +var addr = args[0]; +assert(addr); + +var whichProof = null; +if (args.length > 1) { + whichProof = args[1] +} + +var url = `https://gaia.blockstack.org/hub/${addr}/0/profile.json` +console.log(`url: ${url}`); + +fetch(url) + .then((r) => {return r.json();}, (e) => {console.log(e.stack);}) + .then((j) => {return j[0].decodedToken.payload.claim}, (error) => {console.log(error.stack);}) + .then((p) => { + if (whichProof) { + var idx = 0; + var found = false; + for (idx = 0; idx < p.account.length; idx++) { + if (p.account[idx].service === whichProof) { + found = true; + break; + } + } + if (!found) { + throw new Error("No service: " + whichProof) + } + + var proof = { + 'identifier': p.account[idx].identifier, + 'proof_url': p.account[idx].proofUrl, + 'service': p.account[idx].service, + 'valid': false, + }; + return b.profileServices[whichProof].validateProof(proof, addr).then((a) => {console.log(a)}, (e) => {console.log("error: " + e.stack);}); + } + else { + for (var i = 0; i < p.account.length; i++) { + console.log("Validate " + p.account[i].service + " (" + p.account[i].proofUrl + ")"); + } + + return b.validateProofs(p, addr).then(console.log, (e) => {console.log("validation error: " + e.stack);}) + } + }, + (error) => {console.log(error.stack);}) +