Skip to content

Commit bfa4aa1

Browse files
committed
Implemented test code to allow the creation of a raw transaction from armoryengine.
1 parent 4a5ba68 commit bfa4aa1

File tree

7 files changed

+188
-20
lines changed

7 files changed

+188
-20
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
*.py
1+
*.pyc
22
*.o
33

keepkey_app/SConscript

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ from SCons.Script import *
22
from scons_util import *
33

44
Import('env')
5-
init_project('keepkey_app', env, deps=['crypto'])
5+
init_project('keepkey_app', env, deps=['crypto', 'client'])
66

keepkey_app/local/bitcoin.cpp

+18-3
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,39 @@
22
* @brief Implements the top level bitcoin API.
33
*/
44

5+
#include <cstring>
6+
#include <string>
7+
58
#include <crypto/public/crypto.h>
69

710
#include "bitcoin.h"
811

912
namespace cd {
1013

11-
const char* make_mnemonic() {
14+
std::string make_mnemonic() {
1215
return mnemonic_generate(MNEMONIC_STRENGTH);
1316
}
1417

15-
bool make_wallet(const char* seed) {
18+
HDNode make_wallet(std::string &seed) {
19+
HDNode wallet;
1620

17-
return false;
21+
/*
22+
* The glories of inconsistent constness.
23+
*/
24+
uint8_t *tmp_seed = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(seed.c_str()));
25+
hdnode_from_seed(tmp_seed, seed.length(), &wallet);
26+
27+
return wallet;
1828
}
1929

30+
HDNode make_account_from_wallet(HDNode& wallet) {
31+
32+
}
2033

2134
bool sign_transaction() {
2235
return false;
2336
}
37+
38+
2439
}
2540

keepkey_app/local/bitcoin.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#ifndef BITCOIN_H
22
#define BITCOIN_H
33

4+
#include <string>
5+
6+
#include <crypto/public/crypto.h>
7+
48
/**
59
* Top level API for handling bitcoin workflows.
610
*/
@@ -20,9 +24,10 @@ namespace cd {
2024
*
2125
* @note The mnemonic is generated assuming a strength of 128 bits.
2226
*/
23-
const char* make_mnemonic();
27+
std::string make_mnemonic();
28+
29+
HDNode make_wallet(std::string& seed);
2430

25-
bool make_wallet(const char* seed);
2631

2732
bool sign_transaction();
2833
};

keepkey_app/local/keepkey_main.cpp

+70-13
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,97 @@
1-
#include <assert.h>
2-
#include <stdio.h>
1+
#include <cassert>
2+
#include <cstring>
3+
#include <iomanip>
4+
#include <iostream>
5+
#include <string>
6+
#include <sstream>
7+
#include <vector>
8+
9+
#include <crypto/public/crypto.h>
310

411
#include "bitcoin.h"
512

613

714
/*
815
* Performs user prompting, etc. to make and confirm mnemonic.
916
*/
10-
const char* get_mnemonic() {
17+
std::string get_mnemonic() {
1118

1219
char answer = 'n';
13-
const char* mnemonic = NULL;
14-
20+
std::string mnemonic;
1521

1622
do {
1723
/*
1824
* Generate seed and wait for user affirmation.
1925
*/
2026
mnemonic = cd::make_mnemonic();
2127

22-
assert(mnemonic != 0);
23-
24-
printf("Generated seed: \"%s\"\n", mnemonic);
25-
printf(" Is this OK? y/n: ");
26-
scanf("%c", &answer);
28+
std::cout << "\nGenerated seed: \"" << mnemonic << "\"" << std::endl;
29+
std::cout << " Is this OK? y/n: " << std::endl;
30+
std::cin >> answer;
2731
} while (answer != 'y');
2832

29-
printf("mnemonic CONFIRMED.\n");
33+
std::cout << "mnemonic CONFIRMED." << std::endl;
3034

3135
return mnemonic;
3236
}
3337

38+
bool read_and_sign(std::string &tx_fn) {
39+
/*
40+
FILE* fp = fopen(tx_fn, "r");
41+
42+
if(fp == NULL) {
43+
std::cout << "Transaction file: " << tx_fn << " not found." << std::endl;
44+
return false;
45+
}
46+
*/
47+
return false;
48+
}
49+
50+
std::string hexdump(std::vector<uint8_t> &v) {
51+
std::ostringstream ret;
52+
53+
for(size_t i=0; i < v.size(); i++) {
54+
ret << std::hex << std::setfill('0') << std::setw(2) << v[i];
55+
if(i != v.size()-1) {
56+
ret << " ";
57+
}
58+
}
59+
60+
return ret.str();
61+
}
62+
63+
void print_wallet(HDNode& wallet) {
64+
std::cout << "Created bip32 wallet:" << std::endl;
65+
std::cout << " depth : " << wallet.depth << std::endl;
66+
std::cout << " fingerprint : " << wallet.fingerprint << std::endl;
67+
std::cout << " child_num : " << wallet.child_num << std::endl;
68+
std::vector<uint8_t> v;
69+
v.assign(wallet.chain_code, wallet.chain_code + sizeof(wallet.chain_code));
70+
/*
71+
std::cout << " chain_code : " << hexdump(std::vector<uint8_t>(wallet.chain_code)) << std::endl;
72+
std::cout << " private_key : " << hexdump(wallet.private_key) << std::endl;
73+
std::cout << " public_key : " << hexdump(wallet.public_key) << std::endl;
74+
*/
75+
}
76+
3477
int main(int argc, char *argv[]) {
3578

36-
printf("Making seed ...\n");
37-
const char* mnemonic = get_mnemonic();
79+
std::cout << "Making seed ..." << std::endl;
80+
std::string mnemonic = get_mnemonic();
81+
82+
/**
83+
* Make the bip32 wallet.
84+
*/
85+
HDNode wallet = cd::make_wallet(mnemonic);
86+
print_wallet(wallet);
87+
88+
/*
89+
* Read transaction from file and do it.
90+
*/
91+
std::string transaction_filename("tx.txt");
92+
std::cout << "Reading transaction from " << transaction_filename << " ... " << std::endl;
93+
read_and_sign(transaction_filename);
94+
std::cout << "Transaction signed." << std::endl;
3895

3996
return 0;
4097
}

keepkey_app/test/init.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ARMORY_PATH=~/src/BitcoinArmory
2+
export PYTHONPATH=$PYTHONPATH:$ARMORY_PATH

keepkey_app/test/make_raw_tx.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Run with python make_raw_tx.py --testnet
2+
from armoryengine import *
3+
4+
wallet_name = '/home/tom/.armory/testnet3/armory_2bZuo2ari_.wallet'
5+
6+
#
7+
# Source bitcoin addresses for the transaction
8+
#
9+
source_addr_list = ['myHnTiAfku2nqLBvj4CA5DXiXKR1pdaAkW']
10+
11+
#
12+
# Destination bitcoin address for the transaction.
13+
#
14+
dest_list = [('mk5pFDdTFfnUke4fo9J4weqrX2vKLFokcE', long(1))]
15+
16+
17+
18+
#
19+
# The intermediate file that contains the transaction to be sent to the
20+
# keepkey.
21+
#
22+
tx_unsigned_outfile = 'tx_unsigned_out.dat'
23+
24+
25+
26+
def createTxFromAddrList(walletObj, addrList, recipList, \
27+
fee=0, changeAddr=None):
28+
#
29+
# Warning: Assumes the wallet is synced with the blockchain already.
30+
# Ensure that you've started armory up already, which does that
31+
# automatically at startup.
32+
#
33+
34+
# Check that all addresses are actually in the specified wallet
35+
print '\nVerifying transaction addresses.'
36+
for addr in addrList:
37+
addr160 = addrStr_to_hash160(addr)
38+
if not walletObj.hasAddr(addr160):
39+
raise WalletAddressError, 'Address is not in wallet! [%s]' % addr
40+
41+
#
42+
# Load the block chain
43+
#
44+
start = RightNow()
45+
TheBDM.setBlocking(True)
46+
TheBDM.setOnlineMode(True)
47+
# The setOnlineMode should block until blockchain loading is complete
48+
print 'Loading blockchain took %0.1f sec' % (RightNow() - start)
49+
50+
topBlock = TheBDM.getTopBlockHeight()
51+
print '\n\nCurrent Top Block is:', topBlock
52+
TheBDM.getTopBlockHeader().pprint()
53+
54+
print '\nCollecting Unspent TXOut List...'
55+
# getAddrTxOutList() returns a C++ vector<UnspentTxOut> object, which must
56+
# be converted to a python object using the [:] notation: it's a weird
57+
# consequence of mixing C++ code with python via SWIG...
58+
utxoList = []
59+
for addr in addrList:
60+
addr160 = addrStr_to_hash160(addr)
61+
unspentTxOuts = walletObj.getAddrTxOutList(addr160, 'Spendable')
62+
utxoList.extend(unspentTxOuts[:])
63+
64+
# Display what we found
65+
totalUtxo = sumTxOutList(utxoList)
66+
totalSpend = sum([pair[1] for pair in recipList])
67+
print 'Available: %d unspent outputs from %d addresses: %s BTC' % \
68+
(len(utxoList), len(addrList), coin2str(totalUtxo, ndec=2))
69+
70+
# Print more detailed information
71+
pprintUnspentTxOutList(utxoList, 'Available outputs: ')
72+
73+
def main():
74+
print "Opening armory wallet %s" % wallet_name
75+
wlt = PyBtcWallet().readWalletFile(wallet_name)
76+
TheBDM.registerWallet(wlt)
77+
78+
print "Creating unsigned transaction: "
79+
print " Testnet test bitcoin : " + source_addr_list[0]
80+
print " Tx Unsigned Outfile : " + tx_unsigned_outfile
81+
print " Current blockchain state : " + TheBDM.getBDMState()
82+
raw_tx = createTxFromAddrList(wlt, source_addr_list, dest_list)
83+
84+
execCleanShutdown()
85+
86+
if __name__ == '__main__':
87+
main()
88+
89+

0 commit comments

Comments
 (0)