Browse Source

txdetails and helper functions, proposed fix for #59

https://github.com/jl777/SuperNET/issues/59 required retrieving
additional details from transaction info RPC. both getrawtransaction
and get transaction use the same code path and list transactions also
uses the get transaction path, so all paths should now have the
txdetails fields:

     "category": "receive",
     "amount": 0.50000000,
     "confirmations": 24466,
     "blockhash":
"00000000000000000517ce625737579f91162c46ad9eaccad0f52ca13715b156",
     "blocktime": 1448045745,

     "blockindex": 78,
     "label": "",

the block index and label fields are currently not supported. Also
since iguana has data for all addresses, not just wallet addresses and
including ‘push’ addresses, the ‘category’ field has additional return
possibilities:

‘isp2sh’ is returned for any ‘p2sh’ address, regardless of whether some
or all of the required privkeys to spend the ‘p2sh’ address are in the
wallet. to determine partial or full signature capability would require
interpreting the script in place, and the returned information would
need to indicate conditional states, i.e. cltv, multisig, if/else, etc.
so this part is a won’t fix

for non-p2sh addresses, if it is in the wallet it will return “receive”
or “send” depending on whether the txid/vout outpoint has been spent or
not. for addresses no in the wallet, it will return “unspent” or
“spent”.

Note that a locked wallet might or might not get as far as calling this
txdetails, but if it did, it would return “unspent”/“spent” even for an
address in the wallet as it has no way to know if it is indeed a wallet
address
dPoW2
jl777 8 years ago
parent
commit
d4f19ce7eb
  1. 63
      iguana/iguana_payments.c
  2. 86
      iguana/iguana_realtime.c
  3. 6
      iguana/iguana_wallet.c
  4. 4
      includes/iguana_funcs.h

63
iguana/iguana_payments.c

@ -831,9 +831,44 @@ THREE_STRINGS(bitcoinrpc,verifymessage,address,sig,message)
} else return(clonestr("{\"error\":\"sig is too long\"}"));
}
int64_t iguana_txdetails(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *item,bits256 txid,int32_t vout,int32_t height)
{
struct iguana_block *block; bits256 hash2; uint64_t amount = 0; char coinaddr[64],account[512];
/*{
"category": "receive",
"amount": 0.50000000,
"label": "",
"confirmations": 24466,
"blockhash": "00000000000000000517ce625737579f91162c46ad9eaccad0f52ca13715b156",
"blockindex": 78,
"blocktime": 1448045745,
}*/
jaddbits256(item,"txid",txid);
if ( vout >= 0 )
{
jaddnum(item,"vout",vout);
if ( (amount= iguana_txidamount(myinfo,coin,txid,vout)) != 0 )
jaddnum(item,"amount",dstr(amount));
}
else if ( vout == -1 )
jadd(item,"coinbase",jtrue());
jaddstr(item,"category",iguana_txidcategory(myinfo,coin,account,coinaddr,txid,vout));
if ( account[0] != 0 && jobj(item,"account") == 0 )
jaddstr(item,"account",account);
if ( coinaddr[0] != 0 )
jaddstr(item,"address",coinaddr);
hash2 = iguana_blockhash(coin,height);
jaddbits256(item,"blockhash",hash2);
if ( (block= iguana_blockfind("rawtx",coin,hash2)) != 0 )
jaddnum(item,"blocktime",block->RO.timestamp);
jaddnum(item,"height",height);
jaddnum(item,"confirmations",coin->blocks.hwmchain.height - height);
return(amount);
}
HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose)
{
struct iguana_txid *tx,T; char *txbytes; bits256 checktxid; int32_t len=0,height,extralen=65536; cJSON *retjson,*txobj; uint8_t *extraspace; struct iguana_block *block; bits256 hash2; struct iguana_RTtxid *RTptr;
struct iguana_txid *tx,T; char *txbytes; bits256 checktxid; int32_t len=0,height,extralen=65536; cJSON *retjson,*txobj; uint8_t *extraspace; struct iguana_RTtxid *RTptr;
if ( remoteaddr != 0 )
return(clonestr("{\"error\":\"no remote\"}"));
HASH_FIND(hh,coin->RTdataset,txid.bytes,sizeof(txid),RTptr);
@ -861,12 +896,7 @@ HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose)
free(txbytes);
if ( txobj != 0 )
{
hash2 = iguana_blockhash(coin,height);
jaddbits256(txobj,"blockhash",hash2);
if ( (block= iguana_blockfind("rawtx",coin,hash2)) != 0 )
jaddnum(txobj,"blocktime",block->RO.timestamp);
jaddnum(txobj,"height",height);
jaddnum(txobj,"confirmations",coin->blocks.hwmchain.height - height);
iguana_txdetails(myinfo,coin,txobj,tx->txid,-2,height);
return(jprint(txobj,1));
}
}
@ -894,14 +924,19 @@ HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose)
jaddbits256(retjson,"blockhash",blockhash);
jaddnum(retjson,"height",height);
free(txbytes);
} else jaddstr(retjson,"error","cant find txid in block");
}
else if ( coin->RTheight > 0 )
jaddstr(retjson,"error","cant find txid in block");
else jaddstr(retjson,"error","not in realtime mode yet");
free(blockstr);
free(data);
} else jaddstr(retjson,"error","cant find blockhash");
return(jprint(retjson,1));
}
}
return(clonestr("{\"error\":\"cant find txid\"}"));
if ( coin->RTheight > 0 )
return(clonestr("{\"error\":\"cant find txid\"}"));
else return(clonestr("{\"error\":\"not in realtime mode yet\"}"));
}
int64_t iguana_lockval(int32_t finalized,int64_t locktime)
@ -1005,25 +1040,25 @@ char *iguana_validaterawtx(struct supernet_info *myinfo,struct iguana_info *coin
STRING_AND_INT(bitcoinrpc,validaterawtransaction,rawtx,suppress)
{
uint8_t *extraspace; int32_t extralen=65536;// char *retstr; struct iguana_msgtx msgtx;
uint8_t *extraspace; int32_t extralen=65536; char *retstr; struct iguana_msgtx msgtx;
if ( remoteaddr != 0 )
return(clonestr("{\"error\":\"no remote\"}"));
//cJSON *txobj; char *teststr= "{\"version\":1,\"locktime\":0,\"vin\":[{\"userdata\":\"20fe936da3707c8c4cc7eb0352160ec3f50b9454d46425df6347b2fbc5b2ec87ea00\",\"txid\":\"ee12e50b629d5d45438570fff841d1a2ba7d27f356de4aa06900c9a5e38cf141\",\"vout\":0,\"scriptPubKey\":{\"hex\":\"a9145cc47cc123e3f9b7dce0230009b9d3013a9e0c9687\"},\"suppress\":1,\"redeemScript\":\"6304165daa57b1752102a9669e63ef1ab04913615c2f3887ea3584f81e5f08feee9535b19ab3739d8afdac67a9143805600256ed8498ca1ec426759212e5835e8dc2882103a7b696908f77d69ec89887f8c4a0423b9e80b5974dc43301bd7d8abad07e1211ac68\"}],\"vout\":[{\"satoshis\":\"21821\",\"scriptPubkey\":{\"hex\":\"76a9143ef4734c1141725c095342095f6e0e7748b6c16588ac\"}}]}";
cJSON *txobj; char *teststr= "{\"version\":1,\"locktime\":0,\"vin\":[{\"userdata\":\"206efad760ee54b9b2e2a038a821ef9f950eb0e248545ac202c3e2074cd14f92cb00\",\"txid\":\"3f4759381a62154f2f0eefed1e4433342548ad7b269f912820383b715a39273c\",\"vout\":0,\"scriptPubKey\":{\"hex\":\"a91446dcccef39c1d8c6da2ccc35dce2bfa7ec0d168887\"},\"suppress\":1,\"redeemScript\":\"63041c60aa57b1752103175cf93574c31637b8c2d8acd5319e3cd23761b5e418d32c6bcb194972ba9273ac67a9142d75daf71325feaa593b8f30989e462892189914882102a9669e63ef1ab04913615c2f3887ea3584f81e5f08feee9535b19ab3739d8afdac68\"}],\"vout\":[{\"satoshis\":\"18625\",\"scriptPubkey\":{\"hex\":\"76a914b7128d2ee837cf03e30a2c0e3e0181f7b9669bb688ac\"}}]}";
//cJSON *txobj; char *teststr= "{\"version\":1,\"locktime\":0,\"vin\":[{\"userdata\":\"206efad760ee54b9b2e2a038a821ef9f950eb0e248545ac202c3e2074cd14f92cb00\",\"txid\":\"3f4759381a62154f2f0eefed1e4433342548ad7b269f912820383b715a39273c\",\"vout\":0,\"scriptPubKey\":{\"hex\":\"a91446dcccef39c1d8c6da2ccc35dce2bfa7ec0d168887\"},\"suppress\":1,\"redeemScript\":\"63041c60aa57b1752103175cf93574c31637b8c2d8acd5319e3cd23761b5e418d32c6bcb194972ba9273ac67a9142d75daf71325feaa593b8f30989e462892189914882102a9669e63ef1ab04913615c2f3887ea3584f81e5f08feee9535b19ab3739d8afdac68\"}],\"vout\":[{\"satoshis\":\"18625\",\"scriptPubkey\":{\"hex\":\"76a914b7128d2ee837cf03e30a2c0e3e0181f7b9669bb688ac\"}}]}";
// 01000000013c27395a713b382028919f267bad48253433441eedef0e2f4f15621a3859473f00000000d147304402207ecd423b55c1aa45a994c4eb4337ff0891692fbb69954a9ba024745a99c5272d02207cea696425feb5388153ab7f2608d66a66e4c95cfda2d44e98bc56e25994d3f701206efad760ee54b9b2e2a038a821ef9f950eb0e248545ac202c3e2074cd14f92cb004c6763041c60aa57b1752103175cf93574c31637b8c2d8acd5319e3cd23761b5e418d32c6bcb194972ba9273ac67a9142d75daf71325feaa593b8f30989e462892189914882102a9669e63ef1ab04913615c2f3887ea3584f81e5f08feee9535b19ab3739d8afdac68ffffffff01c1480000000000001976a914b7128d2ee837cf03e30a2c0e3e0181f7b9669bb688ac00000000
// 01000000013c27395a713b382028919f267bad48253433441eedef0e2f4f15621a3859473f00000000fd8b00206efad760ee54b9b2e2a038a821ef9f950eb0e248545ac202c3e2074cd14f92cb004c6763041c60aa57b1752103175cf93574c31637b8c2d8acd5319e3cd23761b5e418d32c6bcb194972ba9273ac67a9142d75daf71325feaa593b8f30989e462892189914882102a9669e63ef1ab04913615c2f3887ea3584f81e5f08feee9535b19ab3739d8afdac68ffffffff01c1480000000000001976a914b7128d2ee837cf03e30a2c0e3e0181f7b9669bb688ac00000000
//cJSON *txobj; char *teststr= "{\"version\":1,\"locktime\":0,\"vin\":[{\"userdata\":\"20ae439d344513eab8e718d8214fe6ae8133b8b5b594afd64da21d0e40b9c37cdd00\",\"txid\":\"2c1320315f4fb519cbf2b4d7b67855013b9a09a85e515df43b41d407a0083b09\",\"vout\":0,\"scriptPubKey\":{\"hex\":\"a9142e7674400d04217f770f2222126dc7fee44b06b487\"},\"suppress\":1,\"redeemScript\":\"63041686a657b1752102a9669e63ef1ab04913615c2f3887ea3584f81e5f08feee9535b19ab3739d8afdac67a914ed74c61c27656abc6c20687c3a9212ffdc6f34cd88210398a4cb9f6ea7c52a4e27455028a95e2e4e397a110fb75f072c2c58a8bdcbf4baac68\"}],\"vout\":[{\"satoshis\":\"16733\",\"scriptPubkey\":{\"hex\":\"76a91454a752f0d71b89d7c014ed0be29ca231c9546f9f88ac\"}}]}";
extraspace = calloc(1,extralen);
if ( (txobj= cJSON_Parse(teststr)) != 0 )
/*if ( (txobj= cJSON_Parse(teststr)) != 0 )
{
bits256 txid;
rawtx = bitcoin_json2hex(myinfo,coin,&txid,txobj,0);
txobj = bitcoin_hex2json(coin,coin->blocks.hwmchain.height,&txid,0,rawtx,extraspace,extralen,0,0,suppress);
printf("RAWTX.(%s) -> (%s)\n",rawtx,jprint(txobj,0));
}
//retstr = iguana_validaterawtx(myinfo,coin,coin->blocks.hwmchain.height,&msgtx,extraspace,extralen,rawtx,0,suppress);
}*/
retstr = iguana_validaterawtx(myinfo,coin,coin->blocks.hwmchain.height,&msgtx,extraspace,extralen,rawtx,0,suppress);
free(extraspace);
return(rawtx);
}

86
iguana/iguana_realtime.c

@ -763,17 +763,23 @@ struct iguana_RTtxid *iguana_RTtxid_create(struct iguana_info *coin,struct iguan
return(RTptr);
}
int64_t _RTgettxout(struct iguana_info *coin,int32_t *height,int32_t *scriptlen,uint8_t *script,uint8_t *rmd160,char *coinaddr,bits256 txid,int32_t vout,int32_t mempool)
int64_t _RTgettxout(struct iguana_info *coin,int32_t *heightp,int32_t *scriptlenp,uint8_t *script,uint8_t *rmd160,char *coinaddr,bits256 txid,int32_t vout,int32_t mempool)
{
int64_t value = 0; struct iguana_RTtxid *RTptr; struct iguana_RTunspent *unspent = 0;
int32_t scriptlen; int64_t value = 0; struct iguana_RTtxid *RTptr; struct iguana_RTunspent *unspent = 0;
HASH_FIND(hh,coin->RTdataset,txid.bytes,sizeof(txid),RTptr);
*heightp = -1;
if ( scriptlenp == 0 )
scriptlenp = &scriptlen;
*scriptlenp = 0;
memset(rmd160,0,20);
coinaddr[0] = 0;
if ( RTptr != 0 && (RTptr->height <= coin->blocks.hwmchain.height || mempool != 0) )
{
if ( vout >= 0 && vout < RTptr->txn_count && (unspent= RTptr->unspents[vout]) != 0 )
{
*height = RTptr->height;
if ( (*scriptlen= unspent->scriptlen) > 0 )
memcpy(script,unspent->script,*scriptlen);
*heightp = RTptr->height;
if ( unspent->spend == 0 && (*scriptlenp= unspent->scriptlen) > 0 )
memcpy(script,unspent->script,*scriptlenp);
memcpy(rmd160,unspent->rmd160,sizeof(unspent->rmd160));
bitcoin_address(coinaddr,coin->chain->pubtype,rmd160,sizeof(unspent->rmd160));
value = unspent->value;
@ -782,6 +788,21 @@ int64_t _RTgettxout(struct iguana_info *coin,int32_t *height,int32_t *scriptlen,
return(value);
}
int32_t _iguana_RTunspentfind(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,int32_t *voutp,uint8_t *spendscript,struct iguana_outpoint outpt,int64_t value)
{
int32_t spendlen = 0; struct iguana_RTunspent *unspent; struct iguana_RTtxid *parent;
if ( outpt.isptr != 0 && (unspent= outpt.ptr) != 0 && (parent= unspent->parent) != 0 )
{
if ( value != unspent->value )
printf("_iguana_RTunspentfind: mismatched value %.8f != %.8f\n",dstr(value),dstr(unspent->value));
if ( (spendlen= unspent->scriptlen) > 0 )
memcpy(spendscript,unspent->script,spendlen);
*txidp = parent->txid;
*voutp = unspent->vout;
}
return(spendlen);
}
int32_t iguana_RTunspentindfind(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,uint8_t *spendscript,int32_t *spendlenp,uint64_t *valuep,int32_t *heightp,bits256 txid,int32_t vout,int32_t lasthdrsi,int32_t mempool)
{
char _coinaddr[64]; uint8_t rmd160[20]; int64_t value;
@ -796,19 +817,52 @@ int32_t iguana_RTunspentindfind(struct supernet_info *myinfo,struct iguana_info
else return(iguana_unspentindfind(myinfo,coin,coinaddr,spendscript,spendlenp,valuep,heightp,txid,vout,lasthdrsi,mempool));
}
int32_t _iguana_RTunspentfind(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,int32_t *voutp,uint8_t *spendscript,struct iguana_outpoint outpt,int64_t value)
int32_t iguana_txidheight(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid)
{
int32_t spendlen = 0; struct iguana_RTunspent *unspent; struct iguana_RTtxid *parent;
if ( outpt.isptr != 0 && (unspent= outpt.ptr) != 0 && (parent= unspent->parent) != 0 )
int32_t spendlen,height = 0; uint64_t value; char coinaddr[64]; uint8_t spendscript[IGUANA_MAXSCRIPTSIZE];
iguana_RTunspentindfind(myinfo,coin,coinaddr,spendscript,&spendlen,&value,&height,txid,0,(coin->firstRTheight/coin->chain->bundlesize) - 1,0);
return(height);
}
int64_t iguana_txidamount(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout)
{
int32_t spendlen,height = 0; uint64_t value; char coinaddr[64]; uint8_t spendscript[IGUANA_MAXSCRIPTSIZE];
iguana_RTunspentindfind(myinfo,coin,coinaddr,spendscript,&spendlen,&value,&height,txid,vout,(coin->firstRTheight/coin->chain->bundlesize) - 1,0);
return(value);
}
char *iguana_txidcategory(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr,bits256 txid,int32_t vout)
{
struct iguana_waccount *wacct; struct iguana_waddress *waddr; int32_t ismine=1,spendlen,height = 0; uint64_t value; uint8_t spendscript[IGUANA_MAXSCRIPTSIZE];
iguana_RTunspentindfind(myinfo,coin,coinaddr,spendscript,&spendlen,&value,&height,txid,vout,(coin->firstRTheight/coin->chain->bundlesize) - 1,0);
account[0] = 0;
if ( coinaddr[0] != 0 )
{
if ( value != unspent->value )
printf("_iguana_RTunspentfind: mismatched value %.8f != %.8f\n",dstr(value),dstr(unspent->value));
if ( (spendlen= unspent->scriptlen) > 0 )
memcpy(spendscript,unspent->script,spendlen);
*txidp = parent->txid;
*voutp = unspent->vout;
}
return(spendlen);
if ( (waddr= iguana_waddresssearch(myinfo,&wacct,coinaddr)) != 0 )
{
if ( waddr->scriptlen != 0 )
return("isp2sh");
else if ( waddr->wifstr[0] != 0 )
ismine = 1;
if ( wacct != 0 )
strcpy(account,wacct->account);
}
} else account[0] = 0;
if ( value != 0 )
{
if ( spendlen == 0 )
{
if ( ismine != 0 )
return("send");
else return("spent");
}
else
{
if ( ismine != 0 )
return("receive");
else return("unspent");
}
} else return("unknown");
}
void iguana_RTunmap(uint8_t *ptr,uint32_t len)

6
iguana/iguana_wallet.c

@ -1576,11 +1576,7 @@ STRING_AND_THREEINTS(bitcoinrpc,listtransactions,account,count,skip,includewatch
}*/
item = cJSON_CreateObject();
jaddstr(item,"account",wacct->account);
jaddstr(item,"address",coinaddr);
jaddbits256(item,"txid",txid);
jaddnum(item,"vout",vout);
//return(bitcoinrpc_getrawtransaction(IGUANA_CALLARGS,txid,1));
iguana_txdetails(myinfo,coin,item,txid,vout,iguana_txidheight(myinfo,coin,txid));
jaddi(retarray,item);
}
}

4
includes/iguana_funcs.h

@ -520,6 +520,10 @@ struct gecko_chain *category_find(bits256 categoryhash,bits256 subhash);
void *category_subscribe(struct supernet_info *myinfo,bits256 category,bits256 keyhash);
char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
char *SuperNET_JSON(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *json,char *remoteaddr,uint16_t port);
int64_t iguana_txdetails(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *item,bits256 txid,int32_t vout,int32_t height);
int32_t iguana_txidheight(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid);
int64_t iguana_txidamount(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout);
char *iguana_txidcategory(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr,bits256 txid,int32_t vout);
struct supernet_info *SuperNET_accountfind(cJSON *json);
cJSON *SuperNET_rosettajson(struct supernet_info *myinfo,bits256 privkey,int32_t showprivs);
double instantdex_aveprice(struct supernet_info *myinfo,struct exchange_quote *sortbuf,int32_t max,double *totalvolp,char *base,char *rel,double basevolume,cJSON *argjson);

Loading…
Cancel
Save