Thanks.
To be honest, I prefer moving txs to/from my cold storage in a raw format.
Then I can easily check if a tx has not been tempered with, doing e.g.:
cat transaction.bin | openssl sha256 -binary | openssl sha256
Besides, before spending them my wallet app needs the original raw data anyway, to make sure that it has the expected ID.
So IMO, it is more convenient for a wallet app to have a tx (carrying an unspent output) as a raw data already.
And if I need to see whats inside a raw tx, I have a tool to display it in a human readable format.
I always use it on a signed tx, before moving it out from my cold storage. Just in case if my wallet would screw something up.
/*
gcc bctrans.c -o bctrans.exe -lcrypto -I /local/ssl/include -L /local/ssl/lib
*/
#include
#include
#include
#include
#include
#include
static unsigned char addr_version = 0x00;
static FILE *f = NULL;
BIGNUM *bn58, dv, mo;
BN_CTX *ctx;
#define SHA256(p,l,o) { \
SHA256_CTX shactx; \
SHA256_Init(&shactx); \
SHA256_Update(&shactx, (p), (l)); \
SHA256_Final((o), &shactx); }
void readfile(unsigned char *p, int len) {
if (!f) {
int c, i;
char s[3];
while (len>0) {
for (i=0;i<2;) {
c = getchar();
if (c==EOF) {
fprintf(stderr, "File too short\n");
exit(1);
}
c = tolower(c);
if (c<='9' && c>='0' || c<='f' && c>='a') s[i++] = (char)c;
}
s[2] = 0;
sscanf(s, "%x", &c);
*p = (unsigned char)c;
p++;
len--;
}
} else {
if (fread(p, 1, len, f)!=len) {
fprintf(stderr, "File too short\n");
fclose(f);
exit(1);
}
}
}
unsigned long long getle(unsigned char *p, int bytes) {
unsigned long long res=0;
while (bytes--) {
res|= ((unsigned long long)(p[bytes]))<<(8*bytes);
}
return res;
}
unsigned long long getvl() {
unsigned char b[8];
readfile(b, 1);
switch (*b) {
case 0xfd:
readfile(b, 2);
return getle(b, 2);
case 0xfe:
readfile(b, 4);
return getle(b, 4);
case 0xff:
readfile(b, 8);
return getle(b, 8);
}
return *b;
}
void prhash(unsigned char *p, unsigned int l) {
while (l--) printf("%02x", p[l]);
}
void hexdump(unsigned char *p, unsigned int l) {
while (l--) printf("%02x", *p++);
}
void printbtcaddr(unsigned char *p) {
static const char *chrs = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
unsigned char mod;
char out[64];
int i=0, j=0;
BIGNUM *bn = BN_bin2bn(p, 25, NULL);
while (!BN_is_zero(bn)) {
BN_div(&dv, &mo, bn, bn58, ctx);
if (BN_bn2bin(&mo, &mod)==0) mod = 0;
out[i++] = chrs[mod];
BN_copy(bn, &dv);
}
BN_free(bn);
while ((*p)==0) {
putchar('1');
p++;
}
while (i--) putchar(out[i]);
}
int main(int argc, char * argv[]) {
static unsigned char buf[0x10000];
unsigned long long i, sl, txcnt, v;
unsigned va, vb;
int x;
long fpos;
char *fname = NULL;
for (x=1; x if (strcmp(argv[x], "-t")==0) {
addr_version = 0x6f; // testnet
} else {
fname = argv[x];
}
}
if (!fname) {
printf("Enter transactions hexdump data:\n");
} else {
f = fopen(fname, "rb");
if (!f) {
fprintf(stderr, "File %s not found\n", fname);
return 1;
}
}
readfile(buf, 4);
printf("Version: %llu\n", getle(buf, 4));
txcnt = getvl();
printf("TX IN cnt: %llu\n", txcnt);
for (i=0; i readfile(buf, 36);
sl = getvl();
printf("%6d) : ", (int)i);
prhash(buf, 32);
printf(" Idx=%2lld sl=%lld", getle(buf+32, 4), sl);
readfile(buf, sl);
readfile(buf, 4);
printf(" seq=%x\n", (unsigned)getle(buf, 4));
}
txcnt = getvl();
printf("TX OUT cnt: %llu\n", txcnt);
ctx = BN_CTX_new();
bn58 = BN_bin2bn("\x3a", 1, NULL);
BN_init(&dv);
BN_init(&mo);
for (i=0; i readfile(buf, 8);
sl = getvl();
v = getle(buf, 8);
va = (unsigned)(v/100000000LL);
vb = (unsigned)(v%100000000LL);
printf("%6d) : %7u.%08u BTC", (int)i, va, vb, sl);
readfile(buf, sl);
if (sl!=25 || memcmp(buf, "\x76\xa9\x14", 3) || buf[23]!=0x88 || buf[24]!=0xac) {
printf(" WARNING! Unexpected SIG_SCRIPT:\n"); hexdump(buf, sl);
} else {
unsigned char dat[25];
unsigned char sha[SHA256_DIGEST_LENGTH];
unsigned char sha2[SHA256_DIGEST_LENGTH];
dat[0] = addr_version; // version
memcpy(dat+1, buf+3, 20);
SHA256(dat, 21, sha);
SHA256(sha, SHA256_DIGEST_LENGTH, sha2);
//printf(" chsum:%02x%02x%02x%02x", sha2[0], sha2[1], sha2[2], sha2[3]);
memcpy(dat+21, sha2, 4);
printf(" to address "); printbtcaddr(dat);
}
putchar('\n');
}
BN_free(bn58);
BN_CTX_free(ctx);
readfile(buf, 4);
printf("Lock Time: %llu\n", getle(buf, 4));
if (f) {
fpos = ftell(f);
fseek(f, 0, SEEK_END);
if (fpos!=ftell(f)) {
printf("WARNING!!! File too long. Only %ld bytes expected (%ld too many)\n",
fpos, ftell(f)-fpos);
} else {
printf("File size checked OK - %ld bytes\n", fpos);
}
fclose(f);
}
return 0;
}