]> Git Repo - VerusCoin.git/blame - src/cc/oracles.cpp
Ensure export finalization edge case
[VerusCoin.git] / src / cc / oracles.cpp
CommitLineData
c926780f 1/******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
3 * *
4 * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
5 * the top-level directory of this distribution for the individual copyright *
6 * holder information and the developer policies on copyright and licensing. *
7 * *
8 * Unless otherwise agreed in a custom licensing agreement, no part of the *
9 * SuperNET software, including this file may be copied, modified, propagated *
10 * or distributed except according to the terms contained in the LICENSE file *
11 * *
12 * Removal or modification of this copyright notice is prohibited. *
13 * *
14 ******************************************************************************/
15
16#include "CCOracles.h"
1c7e29c2 17#include <secp256k1.h>
c926780f 18
19/*
366625ca 20 An oracles CC has the purpose of converting offchain data into onchain data
21 simplest would just be to have a pubkey(s) that are trusted to provide such data, but this wont need to have a CC involved at all and can just be done by convention
22
23 That begs the question, "what would an oracles CC do?"
24 A couple of things come to mind, ie. payments to oracles for future offchain data and maybe some sort of dispute/censoring ability
25
26 first step is to define the data that the oracle is providing. A simple name:description tx can be created to define the name and description of the oracle data.
27 linked to this txid would be two types of transactions:
28 a) oracle providers
29 b) oracle data users
30
31 In order to be resistant to sybil attacks, the feedback mechanism needs to have a cost. combining with the idea of payments for data, the oracle providers will be ranked by actual payments made to each oracle for each data type.
32
26ca942e 33 Implementation notes:
4d55981c 34 In order to maintain good performance even under heavy usage, special marker utxo are used. Actually a pair of them. When a provider registers to be a data provider, a special unspendable normal output is created to allow for quick scanning. Since the marker is based on the oracletxid, it becomes a single address where all the providers can be found.
26ca942e 35
36 A convention is used so that the datafee can be changed by registering again. it is assumed that there wont be too many of these datafee changes. if more than one from the same provider happens in the same block, the lower price is used.
37
38 The other efficiency issue is finding the most recent data point. We want to create a linked list of all data points, going back to the first one. In order to make this efficient, a special and unique per provider/oracletxid baton utxo is used. This should have exactly one utxo, so the search would be a direct lookup and it is passed on from one data point to the next. There is some small chance that the baton utxo is spent in a non-data transaction, so provision is made to allow for recreating a baton utxo in case it isnt found. The baton utxo is a convenience and doesnt affect validation
39
366625ca 40 Required transactions:
41 0) create oracle description -> just needs to create txid for oracle data
42 1) register as oracle data provider with price -> become a registered oracle data provider
43 2) pay provider for N oracle data points -> lock funds for oracle provider
44 3) publish oracle data point -> publish data and collect payment
45
a8c35575 46 The format string is a set of chars with the following meaning:
47 's' -> <256 char string
48 'S' -> <65536 char string
31066d16 49 'd' -> <256 binary data
50 'D' -> <65536 binary data
a8c35575 51 'c' -> 1 byte signed little endian number, 'C' unsigned
52 't' -> 2 byte signed little endian number, 'T' unsigned
53 'i' -> 4 byte signed little endian number, 'I' unsigned
54 'l' -> 8 byte signed little endian number, 'L' unsigned
059f7e44 55 'h' -> 32 byte hash
a8c35575 56
366625ca 57 create:
58 vins.*: normal inputs
59 vout.0: txfee tag to oracle normal address
71d6c154 60 vout.1: change, if any
61 vout.n-1: opreturn with name and description and format for data
366625ca 62
63 register:
64 vins.*: normal inputs
65 vout.0: txfee tag to normal marker address
26ca942e 66 vout.1: baton CC utxo
67 vout.2: change, if any
4d55981c 68 vout.n-1: opreturn with oracletxid, pubkey and price per data point
366625ca 69
70 subscribe:
71 vins.*: normal inputs
72 vout.0: subscription fee to publishers CC address
71d6c154 73 vout.1: change, if any
4d55981c 74 vout.n-1: opreturn with oracletxid, registered provider's pubkey, amount
366625ca 75
76 data:
77 vin.0: normal input
26ca942e 78 vin.1: baton CC utxo (most of the time)
4d55981c 79 vin.2+: subscription or data vout.0
366625ca 80 vout.0: change to publishers CC address
26ca942e 81 vout.1: baton CC utxo
82 vout.2: payment for dataprovider
83 vout.3: change, if any
4d55981c 84 vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
6ea86373 85
4d55981c 86 data (without payment) this is not needed as publisher can pay themselves!
26ca942e 87 vin.0: normal input
88 vin.1: baton CC utxo
89 vout.0: txfee to publishers normal address
90 vout.1: baton CC utxo
91 vout.2: change, if any
4d55981c 92 vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
26ca942e 93
c926780f 94*/
95
96// start of consensus code
97
cb96789e 98
99CScript EncodeOraclesCreateOpRet(uint8_t funcid,std::string name,std::string description,std::string format)
100{
101 CScript opret; uint8_t evalcode = EVAL_ORACLES;
3caaec31 102 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << name << format << description);
cb96789e 103 return(opret);
104}
105
106uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format)
107{
5a53af78 108 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid;
cb96789e 109 GetOpReturnData(scriptPubKey,vopret);
110 script = (uint8_t *)vopret.data();
111 if ( script[0] == EVAL_ORACLES )
112 {
113 if ( script[1] == 'C' )
114 {
3caaec31 115 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> name; ss >> format; ss >> description) != 0 )
cb96789e 116 {
117 return(script[1]);
118 } else fprintf(stderr,"DecodeOraclesCreateOpRet unmarshal error for C\n");
119 }
120 }
121 return(0);
122}
123
124CScript EncodeOraclesOpRet(uint8_t funcid,uint256 oracletxid,CPubKey pk,int64_t num)
125{
126 CScript opret; uint8_t evalcode = EVAL_ORACLES;
127 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << pk << num);
128 return(opret);
129}
130
131uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num)
132{
133 std::vector<uint8_t> vopret; uint8_t *script,e,f;
134 GetOpReturnData(scriptPubKey,vopret);
135 script = (uint8_t *)vopret.data();
136 if ( vopret.size() > 1 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> pk; ss >> num) != 0 )
137 {
138 if ( e == EVAL_ORACLES && (f == 'R' || f == 'S') )
139 return(f);
140 }
141 return(0);
142}
143
26ca942e 144CScript EncodeOraclesData(uint8_t funcid,uint256 oracletxid,uint256 batontxid,CPubKey pk,std::vector <uint8_t>data)
cb96789e 145{
146 CScript opret; uint8_t evalcode = EVAL_ORACLES;
26ca942e 147 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << batontxid << pk << data);
cb96789e 148 return(opret);
149}
150
26ca942e 151uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data)
cb96789e 152{
153 std::vector<uint8_t> vopret; uint8_t *script,e,f;
154 GetOpReturnData(scriptPubKey,vopret);
155 script = (uint8_t *)vopret.data();
26ca942e 156 if ( vopret.size() > 1 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> batontxid; ss >> pk; ss >> data) != 0 )
cb96789e 157 {
158 if ( e == EVAL_ORACLES && f == 'D' )
159 return(f);
160 }
161 return(0);
162}
163
7af451d0 164CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp)
26ca942e 165{
1c7e29c2 166 static secp256k1_context *ctx;
2e32decd 167 size_t clen = CPubKey::PUBLIC_KEY_SIZE;
1c7e29c2 168 secp256k1_pubkey pubkey; CPubKey batonpk; uint8_t priv[32]; int32_t i;
169 if ( ctx == 0 )
170 ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
26ca942e 171 Myprivkey(priv);
e0bea545 172 cp->evalcode2 = EVAL_ORACLES;
26ca942e 173 for (i=0; i<32; i++)
1c7e29c2 174 cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]);
0f7c30b9 175 while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 )
176 {
177 for (i=0; i<32; i++)
178 fprintf(stderr,"%02x",cp->unspendablepriv2[i]);
179 fprintf(stderr," invalid privkey\n");
4040391f 180 if ( secp256k1_ec_privkey_tweak_add(ctx,cp->unspendablepriv2,priv) != 0 )
181 break;
0f7c30b9 182 }
13a44e03 183 if ( secp256k1_ec_pubkey_create(ctx,&pubkey,cp->unspendablepriv2) != 0 )
26ca942e 184 {
2e32decd 185 secp256k1_ec_pubkey_serialize(ctx,(unsigned char*)batonpk.begin(),&clen,&pubkey,SECP256K1_EC_COMPRESSED);
186 cp->unspendablepk2 = batonpk;
7af451d0 187 Getscriptaddress(batonaddr,MakeCC1vout(cp->evalcode,0,batonpk).scriptPubKey);
912c8a4d 188 //fprintf(stderr,"batonpk.(%s) -> %s\n",(char *)HexStr(batonpk).c_str(),batonaddr);
1c7e29c2 189 strcpy(cp->unspendableaddr2,batonaddr);
190 } else fprintf(stderr,"error creating pubkey\n");
26ca942e 191 return(batonpk);
192}
193
194int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publisher)
195{
a3532c80 196 uint256 txid,oracletxid,hashBlock; int64_t datafee=0,dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk;
26ca942e 197 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
198 SetCCunspents(unspentOutputs,markeraddr);
199 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
200 {
201 txid = it->first.txhash;
202 vout = (int32_t)it->first.index;
a3532c80 203 height = (int32_t)it->second.blockHeight;
68ea3129 204 if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
26ca942e 205 {
206 if ( DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,pk,dfee) == 'R' )
207 {
208 if ( oracletxid == reforacletxid && pk == publisher )
209 {
210 if ( height > dheight || (height == dheight && dfee < datafee) )
211 {
212 dheight = height;
213 datafee = dfee;
68ea3129 214 if ( 0 && dheight != 0 )
756e9cf7 215 fprintf(stderr,"set datafee %.8f height.%d\n",(double)datafee/COIN,height);
26ca942e 216 }
217 }
218 }
219 }
220 }
221 return(datafee);
222}
223
059f7e44 224int64_t OracleDatafee(CScript &scriptPubKey,uint256 oracletxid,CPubKey publisher)
225{
612f676a 226 CTransaction oracletx; char markeraddr[64]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0;
059f7e44 227 if ( myGetTransaction(oracletxid,oracletx,hashBlock) != 0 && (numvouts= oracletx.vout.size()) > 0 )
228 {
229 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
230 {
612f676a 231 CCtxidaddr(markeraddr,oracletxid);
059f7e44 232 datafee = OracleCurrentDatafee(oracletxid,markeraddr,publisher);
233 }
234 }
235 return(datafee);
236}
237
50dfc224 238static uint256 myIs_baton_spentinmempool(uint256 batontxid,int32_t batonvout)
239{
240 BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
241 {
242 const CTransaction &tx = e.GetTx();
243 if ( tx.vout.size() > 0 && tx.vin.size() > 1 && batontxid == tx.vin[1].prevout.hash && batonvout == tx.vin[1].prevout.n )
244 {
4ad41419 245 const uint256 &txid = tx.GetHash();
7fb5e4aa 246 //char str[65]; fprintf(stderr,"found baton spent in mempool %s\n",uint256_str(str,txid));
50dfc224 247 return(txid);
248 }
249 }
250 return(batontxid);
251}
252
059f7e44 253uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 reforacletxid,char *batonaddr,CPubKey publisher,std::vector <uint8_t> &dataarg)
26ca942e 254{
3fd708a6 255 uint256 txid,oracletxid,hashBlock,btxid,batontxid = zeroid; int64_t dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk; uint8_t *ptr; std::vector<uint8_t> vopret,data;
26ca942e 256 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
257 SetCCunspents(unspentOutputs,batonaddr);
258 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
259 {
260 txid = it->first.txhash;
261 vout = (int32_t)it->first.index;
a3532c80 262 height = (int32_t)it->second.blockHeight;
26ca942e 263 if ( it->second.satoshis != txfee )
718aa08e 264 {
265 fprintf(stderr,"it->second.satoshis %llu != %llu txfee\n",(long long)it->second.satoshis,(long long)txfee);
26ca942e 266 continue;
718aa08e 267 }
68ea3129 268 if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
26ca942e 269 {
a3532c80 270 GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
26ca942e 271 if ( vopret.size() > 2 )
272 {
273 ptr = (uint8_t *)vopret.data();
059f7e44 274 if ( (ptr[1] == 'D' && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D') || (ptr[1] == 'R' && DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,pk,dfee) == 'R') )
26ca942e 275 {
276 if ( oracletxid == reforacletxid && pk == publisher )
277 {
278 if ( height > dheight )
279 {
280 dheight = height;
281 batontxid = txid;
059f7e44 282 if ( ptr[1] == 'D' )
283 dataarg = data;
9d9ad70f 284 //char str[65]; fprintf(stderr,"set batontxid %s height.%d\n",uint256_str(str,batontxid),height);
26ca942e 285 }
286 }
287 }
288 }
289 }
290 }
50dfc224 291 while ( myIsutxo_spentinmempool(batontxid,1) != 0 )
292 batontxid = myIs_baton_spentinmempool(batontxid,1);
26ca942e 293 return(batontxid);
294}
295
3a669423 296uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
297{
298 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
ccf003ff 299 CTransaction regtx; uint256 hash,txid,batontxid,oracletxid; CPubKey pk; int32_t numvouts,height,maxheight=0; int64_t datafee; char markeraddr[64],batonaddr[64]; std::vector <uint8_t> data; struct CCcontract_info *cp,C;
1410c4c8 300 batontxid = zeroid;
3a669423 301 cp = CCinit(&C,EVAL_ORACLES);
e06ad50d 302 CCtxidaddr(markeraddr,reforacletxid);
3a669423 303 SetCCunspents(unspentOutputs,markeraddr);
50dfc224 304 //char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk));
3a669423 305 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
306 {
307 txid = it->first.txhash;
50dfc224 308 //fprintf(stderr,"check %s\n",uint256_str(str,txid));
3a669423 309 height = (int32_t)it->second.blockHeight;
1410c4c8 310 if ( myGetTransaction(txid,regtx,hash) != 0 )
3a669423 311 {
1410c4c8 312 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid && pk == refpk )
3a669423 313 {
1410c4c8 314 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
315 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
316 break;
3a669423 317 }
318 }
319 }
1410c4c8 320 return(batontxid);
3a669423 321}
322
059f7e44 323int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen)
26ca942e 324{
7d6b0f58 325 char _str[65]; int32_t sflag = 0,i,val32,len = 0,slen = 0,dlen = 0; uint32_t uval32; uint16_t uval16; int16_t val16; int64_t val = 0; uint64_t uval = 0;
059f7e44 326 *valp = 0;
327 *hashp = zeroid;
7d6b0f58 328 if ( str != 0 )
329 str[0] = 0;
059f7e44 330 switch ( fmt )
26ca942e 331 {
059f7e44 332 case 's': slen = data[offset++]; break;
333 case 'S': slen = data[offset++]; slen |= ((int32_t)data[offset++] << 8); break;
7d6b0f58 334 case 'd': dlen = data[offset++]; break;
335 case 'D': dlen = data[offset++]; dlen |= ((int32_t)data[offset++] << 8); break;
059f7e44 336 case 'c': len = 1; sflag = 1; break;
337 case 'C': len = 1; break;
338 case 't': len = 2; sflag = 1; break;
339 case 'T': len = 2; break;
340 case 'i': len = 4; sflag = 1; break;
341 case 'I': len = 4; break;
342 case 'l': len = 8; sflag = 1; break;
343 case 'L': len = 8; break;
344 case 'h': len = 32; break;
345 default: return(-1); break;
346 }
347 if ( slen != 0 )
348 {
349 if ( str != 0 )
26ca942e 350 {
7d6b0f58 351 if ( slen < IGUANA_MAXSCRIPTSIZE && offset+slen <= datalen )
059f7e44 352 {
7d6b0f58 353 for (i=0; i<slen; i++)
354 str[i] = data[offset++];
355 str[i] = 0;
356 } else return(-1);
357 }
358 }
359 else if ( dlen != 0 )
360 {
361 if ( str != 0 )
362 {
363 if ( dlen < IGUANA_MAXSCRIPTSIZE && offset+dlen <= datalen )
364 {
365 for (i=0; i<dlen; i++)
366 sprintf(&str[i<<1],"%02x",data[offset++]);
367 str[i] = 0;
368 } else return(-1);
26ca942e 369 }
370 }
059f7e44 371 else if ( len != 0 && len+offset <= datalen )
372 {
373 if ( len == 32 )
374 {
375 iguana_rwbignum(0,&data[offset],len,(uint8_t *)hashp);
376 if ( str != 0 )
377 sprintf(str,"%s",uint256_str(_str,*hashp));
378 }
379 else
380 {
381 if ( sflag != 0 )
382 {
383 switch ( len )
384 {
385 case 1: val = (int8_t)data[offset]; break;
386 case 2: iguana_rwnum(0,&data[offset],len,(void *)&val16); val = val16; break;
387 case 4: iguana_rwnum(0,&data[offset],len,(void *)&val32); val = val32; break;
388 case 8: iguana_rwnum(0,&data[offset],len,(void *)&val); break;
389 }
390 if ( str != 0 )
391 sprintf(str,"%lld",(long long)val);
392 *valp = val;
393 }
394 else
395 {
396 switch ( len )
397 {
398 case 1: uval = data[offset]; break;
399 case 2: iguana_rwnum(0,&data[offset],len,(void *)&uval16); uval = uval16; break;
400 case 4: iguana_rwnum(0,&data[offset],len,(void *)&uval32); uval = uval32; break;
401 case 8: iguana_rwnum(0,&data[offset],len,(void *)&uval); break;
402 }
403 if ( str != 0 )
404 sprintf(str,"%llu",(long long)uval);
405 *valp = (int64_t)uval;
406 }
407 }
408 offset += len;
409 } else return(-1);
410 return(offset);
411}
412
c6636cf0 413int64_t _correlate_price(int64_t *prices,int32_t n,int64_t price)
059f7e44 414{
415 int32_t i,count = 0; int64_t diff,threshold = (price >> 8);
416 for (i=0; i<n; i++)
417 {
418 if ( (diff= (price - prices[i])) < 0 )
419 diff = -diff;
420 if ( diff <= threshold )
421 count++;
422 }
423 if ( count < (n >> 1) )
424 return(0);
d898dbce 425 else return(price);
059f7e44 426}
427
d5f527a7 428int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
059f7e44 429{
430 int32_t i,j; int64_t price = 0;
431 if ( n == 1 )
432 return(prices[0]);
433 for (i=0; i<n; i++)
434 {
435 j = (height + i) % n;
436 if ( prices[j] != 0 && (price= _correlate_price(prices,n,prices[j])) != 0 )
437 break;
438 }
439 for (i=0; i<n; i++)
440 fprintf(stderr,"%llu ",(long long)prices[i]);
441 fprintf(stderr,"-> %llu ht.%d\n",(long long)price,height);
16bc940e 442 return (int64_t)price;
059f7e44 443}
444
d5f527a7 445int64_t OracleCorrelatedPrice(int32_t height,std::vector <int64_t> origprices)
059f7e44 446{
6b078fa6 447 std::vector <int64_t> sorted; int32_t i,n; int64_t *prices,price;
448 if ( (n= origprices.size()) == 1 )
449 return(origprices[0]);
a912c7e8 450 std::sort(origprices.begin(), origprices.end());
451 prices = (int64_t *)calloc(n,sizeof(*prices));
6b078fa6 452 i = 0;
453 for (std::vector<int64_t>::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
a912c7e8 454 prices[i++] = *it;
d5f527a7 455 price = correlate_price(height,prices,i);
6b078fa6 456 free(prices);
457 return(price);
458}
459
460int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey pk,int32_t height,std::vector <uint8_t> data,int32_t maxheight)
461{
462 struct oracleprice_info item; int32_t flag = 0;
bedac1d5 463 for (std::vector<struct oracleprice_info>::iterator it=publishers.begin(); it!=publishers.end(); it++)
059f7e44 464 {
a5faf9e9 465 if ( pk == it->pk )
059f7e44 466 {
6b078fa6 467 flag = 1;
a912c7e8 468 if ( height > it->height )
6b078fa6 469 {
a5faf9e9 470 it->height = height;
471 it->data = data;
6b078fa6 472 return(height);
473 }
059f7e44 474 }
475 }
6b078fa6 476 if ( flag == 0 )
477 {
478 item.pk = pk;
479 item.data = data;
480 item.height = height;
481 publishers.push_back(item);
482 return(height);
483 } else return(0);
059f7e44 484}
485
486int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
487{
488 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
3515c101 489 CTransaction regtx; uint256 hash,txid,oracletxid,batontxid; CPubKey pk; int32_t i,ht,maxheight=0; int64_t datafee,price; char batonaddr[64]; std::vector <uint8_t> data; struct CCcontract_info *cp,C; std::vector <struct oracleprice_info> publishers; std::vector <int64_t> prices;
6b078fa6 490 if ( format[0] != 'L' )
491 return(0);
d898dbce 492 cp = CCinit(&C,EVAL_ORACLES);
059f7e44 493 SetCCunspents(unspentOutputs,markeraddr);
494 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
495 {
496 txid = it->first.txhash;
a912c7e8 497 ht = (int32_t)it->second.blockHeight;
6b078fa6 498 if ( myGetTransaction(txid,regtx,hash) != 0 )
059f7e44 499 {
c6636cf0 500 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid )
059f7e44 501 {
6b078fa6 502 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
503 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
a912c7e8 504 if ( batontxid != zeroid && (ht= oracleprice_add(publishers,pk,ht,data,maxheight)) > maxheight )
6b078fa6 505 maxheight = ht;
059f7e44 506 }
507 }
508 }
6b078fa6 509 if ( maxheight > 10 )
510 {
511 for (std::vector<struct oracleprice_info>::const_iterator it=publishers.begin(); it!=publishers.end(); it++)
512 {
a5faf9e9 513 if ( it->height >= maxheight-10 )
6b078fa6 514 {
a5faf9e9 515 oracle_format(&hash,&price,0,'L',(uint8_t *)it->data.data(),0,(int32_t)it->data.size());
6b078fa6 516 if ( price != 0 )
517 prices.push_back(price);
518 }
519 }
a912c7e8 520 return(OracleCorrelatedPrice(height,prices));
6b078fa6 521 }
522 return(0);
26ca942e 523}
524
c926780f 525int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
526{
4b19e190 527 //char destaddr[64];
c926780f 528 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
529 {
4b19e190 530 //if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
c926780f 531 return(tx.vout[v].nValue);
532 }
533 return(0);
534}
535
26ac5473 536bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,uint256 oracletxid,CPubKey publisher,int64_t datafee)
c926780f 537{
538 static uint256 zerohash;
4d55981c 539 CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; CScript scriptPubKey;
c926780f 540 numvins = tx.vin.size();
541 numvouts = tx.vout.size();
4d55981c 542 if ( OracleDatafee(scriptPubKey,oracletxid,publisher) != datafee )
543 return eval->Invalid("mismatched datafee");
544 scriptPubKey = MakeCC1vout(cp->evalcode,0,publisher).scriptPubKey;
c926780f 545 for (i=0; i<numvins; i++)
546 {
547 //fprintf(stderr,"vini.%d\n",i);
548 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
549 {
545c8190 550 if ( i == 0 )
551 return eval->Invalid("unexpected vin.0 is CC");
c926780f 552 //fprintf(stderr,"vini.%d check mempool\n",i);
545c8190 553 else if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
c926780f 554 return eval->Invalid("cant find vinTx");
555 else
556 {
557 //fprintf(stderr,"vini.%d check hash and vout\n",i);
b2da43cf 558 //if ( hashBlock == zerohash )
559 // return eval->Invalid("cant Oracles from mempool");
c926780f 560 if ( (assetoshis= IsOraclesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
4d55981c 561 {
562 if ( i == 1 && vinTx.vout[1].scriptPubKey != tx.vout[1].scriptPubKey )
563 return eval->Invalid("baton violation");
564 else if ( i != 1 && scriptPubKey == vinTx.vout[tx.vin[i].prevout.n].scriptPubKey )
565 inputs += assetoshis;
566 }
c926780f 567 }
568 }
545c8190 569 else if ( i != 0 )
570 return eval->Invalid("vin0 not normal");
571
c926780f 572 }
573 for (i=0; i<numvouts; i++)
574 {
575 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
576 if ( (assetoshis= IsOraclesvout(cp,tx,i)) != 0 )
545c8190 577 {
578 if ( i < 2 )
579 {
580 if ( i == 0 )
581 {
582 if ( tx.vout[0].scriptPubKey == scriptPubKey )
583 outputs += assetoshis;
584 else return eval->Invalid("invalid CC vout CC destination");
585 }
586 }
587 }
c926780f 588 }
26ac5473 589 if ( inputs != outputs+datafee )
c926780f 590 {
26ac5473 591 fprintf(stderr,"inputs %llu vs outputs %llu + datafee %llu\n",(long long)inputs,(long long)outputs,(long long)datafee);
592 return eval->Invalid("mismatched inputs != outputs + datafee");
c926780f 593 }
594 else return(true);
595}
596
4ecaf167 597bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn, bool fulfilled)
c926780f 598{
4d55981c 599 uint256 txid,oracletxid,batontxid; uint64_t txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts; uint8_t *script; std::vector<uint8_t> vopret,data; CScript scriptPubKey; CPubKey publisher;
c926780f 600 numvins = tx.vin.size();
601 numvouts = tx.vout.size();
602 preventCCvins = preventCCvouts = -1;
603 if ( numvouts < 1 )
604 return eval->Invalid("no vouts");
605 else
606 {
4d55981c 607 txid = tx.GetHash();
608 GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
835333f2 609 if ( vopret.size() > 2 )
c926780f 610 {
4d55981c 611 script = (uint8_t *)vopret.data();
612 switch ( script[1] )
c926780f 613 {
4d55981c 614 case 'C': // create
615 // vins.*: normal inputs
616 // vout.0: txfee tag to oracle normal address
617 // vout.1: change, if any
618 // vout.n-1: opreturn with name and description and format for data
619 return eval->Invalid("unexpected OraclesValidate for create");
620 break;
621 case 'R': // register
622 // vins.*: normal inputs
623 // vout.0: txfee tag to normal marker address
624 // vout.1: baton CC utxo
625 // vout.2: change, if any
626 // vout.n-1: opreturn with createtxid, pubkey and price per data point
627 return eval->Invalid("unexpected OraclesValidate for register");
628 break;
629 case 'S': // subscribe
630 // vins.*: normal inputs
631 // vout.0: subscription fee to publishers CC address
632 // vout.1: change, if any
633 // vout.n-1: opreturn with createtxid, registered provider's pubkey, amount
634 return eval->Invalid("unexpected OraclesValidate for subscribe");
635 break;
636 case 'D': // data
637 // vin.0: normal input
638 // vin.1: baton CC utxo (most of the time)
639 // vin.2+: subscription vout.0
640 // vout.0: change to publishers CC address
641 // vout.1: baton CC utxo
642 // vout.2: payment for dataprovider
643 // vout.3: change, if any
644 if ( numvins >= 2 && numvouts >= 3 && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,batontxid,publisher,data) == 'D' )
645 {
26ac5473 646 if ( OraclesDataValidate(cp,eval,tx,oracletxid,publisher,tx.vout[2].nValue) != 0 )
4d55981c 647 {
4d55981c 648 return(true);
545c8190 649 } else return(false);
4d55981c 650 }
651 return eval->Invalid("unexpected OraclesValidate 'D' tx invalid");
652 break;
c926780f 653 }
654 }
4d55981c 655 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
c926780f 656 }
4d55981c 657 return(true);
c926780f 658}
659// end of consensus code
660
661// helper functions for rpc calls in rpcwallet.cpp
662
53314c07 663int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
c926780f 664{
665 char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
666 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
667 GetCCaddress(cp,coinaddr,pk);
668 SetCCunspents(unspentOutputs,coinaddr);
669 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
670 {
671 txid = it->first.txhash;
672 vout = (int32_t)it->first.index;
7fb5e4aa 673 //char str[65]; fprintf(stderr,"oracle check %s/v%d\n",uint256_str(str,txid),vout);
c926780f 674 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
675 {
a2094466 676 // get valid CC payments
4d55981c 677 if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
c926780f 678 {
679 if ( total != 0 && maxinputs != 0 )
680 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
681 nValue = it->second.satoshis;
682 totalinputs += nValue;
683 n++;
684 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
685 break;
5b7e7959 686 } //else fprintf(stderr,"nValue %.8f or utxo memspent\n",(double)nValue/COIN);
4b19e190 687 } else fprintf(stderr,"couldnt find transaction\n");
c926780f 688 }
689 return(totalinputs);
690}
691
718aa08e 692int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubKey publisher)
c926780f 693{
cb96789e 694 char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock,subtxid; CTransaction subtx;
366625ca 695 std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
718aa08e 696 GetCCaddress(cp,coinaddr,publisher);
366625ca 697 SetCCtxids(addressIndex,coinaddr);
9d9ad70f 698 //fprintf(stderr,"scan lifetime of %s\n",coinaddr);
366625ca 699 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
700 {
701 txid = it->first.txhash;
702 if ( GetTransaction(txid,subtx,hashBlock,false) != 0 )
703 {
718aa08e 704 if ( subtx.vout.size() > 0 && DecodeOraclesOpRet(subtx.vout[subtx.vout.size()-1].scriptPubKey,subtxid,pk,num) == 'S' && subtxid == oracletxid && pk == publisher )
366625ca 705 {
706 total += subtx.vout[0].nValue;
707 }
708 }
709 }
710 return(total);
711}
712
713std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format)
714{
715 CMutableTransaction mtx; CPubKey mypk,Oraclespk; struct CCcontract_info *cp,C;
c926780f 716 cp = CCinit(&C,EVAL_ORACLES);
366625ca 717 if ( name.size() > 32 || description.size() > 4096 || format.size() > 4096 )
718 {
719 fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
720 return("");
721 }
c926780f 722 if ( txfee == 0 )
723 txfee = 10000;
366625ca 724 mypk = pubkey2pk(Mypubkey());
c926780f 725 Oraclespk = GetUnspendable(cp,0);
366625ca 726 if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
727 {
728 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(Oraclespk)) << OP_CHECKSIG));
729 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesCreateOpRet('C',name,description,format)));
730 }
731 return("");
732}
733
734std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
735{
612f676a 736 CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64];
366625ca 737 cp = CCinit(&C,EVAL_ORACLES);
366625ca 738 if ( txfee == 0 )
739 txfee = 10000;
059f7e44 740 if ( datafee < txfee )
741 {
742 fprintf(stderr,"datafee must be txfee or more\n");
743 return("");
744 }
c926780f 745 mypk = pubkey2pk(Mypubkey());
7af451d0 746 batonpk = OracleBatonPk(batonaddr,cp);
612f676a 747 markerpubkey = CCtxidaddr(markeraddr,oracletxid);
26ca942e 748 if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
366625ca 749 {
ae846fcc 750 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
26ca942e 751 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
366625ca 752 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,datafee)));
753 }
754 return("");
755}
756
757std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount)
758{
612f676a 759 CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64];
366625ca 760 cp = CCinit(&C,EVAL_ORACLES);
366625ca 761 if ( txfee == 0 )
762 txfee = 10000;
763 mypk = pubkey2pk(Mypubkey());
612f676a 764 markerpubkey = CCtxidaddr(markeraddr,oracletxid);
366625ca 765 if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 )
766 {
767 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher));
ae846fcc 768 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
cb96789e 769 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('S',oracletxid,mypk,amount)));
366625ca 770 }
c926780f 771 return("");
772}
773
366625ca 774std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> data)
c926780f 775{
059f7e44 776 CMutableTransaction mtx; CScript pubKey; CPubKey mypk,batonpk; int64_t datafee,inputs,CCchange = 0; struct CCcontract_info *cp,C; uint256 batontxid; char coinaddr[64],batonaddr[64]; std::vector <uint8_t> prevdata;
c926780f 777 cp = CCinit(&C,EVAL_ORACLES);
cb96789e 778 mypk = pubkey2pk(Mypubkey());
366625ca 779 if ( data.size() > 8192 )
780 {
781 fprintf(stderr,"datasize %d is too big\n",(int32_t)data.size());
782 return("");
783 }
a2094466 784 if ( (datafee= OracleDatafee(pubKey,oracletxid,mypk)) <= 0 )
366625ca 785 {
786 fprintf(stderr,"datafee %.8f is illegal\n",(double)datafee/COIN);
787 return("");
788 }
c926780f 789 if ( txfee == 0 )
790 txfee = 10000;
366625ca 791 GetCCaddress(cp,coinaddr,mypk);
c5c1aaa1 792 if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) // have enough funds even if baton utxo not there
c926780f 793 {
7af451d0 794 batonpk = OracleBatonPk(batonaddr,cp);
059f7e44 795 batontxid = OracleBatonUtxo(txfee,cp,oracletxid,batonaddr,mypk,prevdata);
26ca942e 796 if ( batontxid != zeroid ) // not impossible to fail, but hopefully a very rare event
797 mtx.vin.push_back(CTxIn(batontxid,1,CScript()));
718aa08e 798 else fprintf(stderr,"warning: couldnt find baton utxo %s\n",batonaddr);
4b19e190 799 if ( (inputs= AddOracleInputs(cp,mtx,mypk,datafee,60)) > 0 )
366625ca 800 {
801 if ( inputs > datafee )
802 CCchange = (inputs - datafee);
803 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
26ca942e 804 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
805 mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
806 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data)));
4084a149 807 } else fprintf(stderr,"couldnt find enough oracle inputs, limit 1 per utxo\n");
c46ccfc3 808 } else fprintf(stderr,"couldnt add normal inputs\n");
c926780f 809 return("");
810}
811
26ca942e 812UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatlen)
813{
7d6b0f58 814 UniValue obj(UniValue::VARR); uint256 hash; int32_t i,j=0; int64_t val; char str[IGUANA_MAXSCRIPTSIZE*2+1];
26ca942e 815 for (i=0; i<formatlen && j<datalen; i++)
816 {
817 str[0] = 0;
059f7e44 818 j = oracle_format(&hash,&val,str,format[i],data,j,datalen);
26ca942e 819 if ( j < 0 )
820 break;
821 obj.push_back(str);
822 if ( j >= datalen )
823 break;
824 }
825 return(obj);
826}
827
828UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num)
829{
760ff4b8 830 UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,oracletx; uint256 hashBlock,btxid,oracletxid; CPubKey pk; std::string name,description,format; int32_t numvouts,n=0; std::vector<uint8_t> data; char *formatstr = 0;
26ca942e 831 result.push_back(Pair("result","success"));
832 if ( GetTransaction(reforacletxid,oracletx,hashBlock,false) != 0 && (numvouts=oracletx.vout.size()) > 0 )
833 {
834 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
835 {
836 while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 )
837 {
838 if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid )
839 {
840 if ( (formatstr= (char *)format.c_str()) == 0 )
3fd708a6 841 formatstr = (char *)"";
26ca942e 842 a.push_back(OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()));
843 batontxid = btxid;
844 if ( ++n >= num )
845 break;
846 } else break;
847 }
848 }
849 }
850 result.push_back(Pair("samples",a));
851 return(result);
852}
853
366625ca 854UniValue OracleInfo(uint256 origtxid)
c926780f 855{
26ca942e 856 UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ);
857 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
612f676a 858 CMutableTransaction mtx; CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
c926780f 859 cp = CCinit(&C,EVAL_ORACLES);
612f676a 860 CCtxidaddr(markeraddr,origtxid);
fb6f9ce9 861 if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
366625ca 862 {
fb6f9ce9 863 if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
366625ca 864 {
26ca942e 865 result.push_back(Pair("result","success"));
366625ca 866 result.push_back(Pair("txid",uint256_str(str,origtxid)));
867 result.push_back(Pair("name",name));
868 result.push_back(Pair("description",description));
26ca942e 869 result.push_back(Pair("format",format));
366625ca 870 result.push_back(Pair("marker",markeraddr));
26ca942e 871 SetCCunspents(unspentOutputs,markeraddr);
872 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
366625ca 873 {
874 txid = it->first.txhash;
875 if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
876 {
fb6f9ce9 877 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
366625ca 878 {
17a9434a 879 obj.push_back(Pair("publisher",pubkey33_str(str,(uint8_t *)pk.begin())));
26ca942e 880 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
059f7e44 881 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
26ca942e 882 obj.push_back(Pair("baton",batonaddr));
883 obj.push_back(Pair("batontxid",uint256_str(str,batontxid)));
366625ca 884 funding = LifetimeOraclesFunds(cp,oracletxid,pk);
885 sprintf(numstr,"%.8f",(double)funding/COIN);
886 obj.push_back(Pair("lifetime",numstr));
53314c07 887 funding = AddOracleInputs(cp,mtx,pk,0,0);
366625ca 888 sprintf(numstr,"%.8f",(double)funding/COIN);
889 obj.push_back(Pair("funds",numstr));
890 sprintf(numstr,"%.8f",(double)datafee/COIN);
891 obj.push_back(Pair("datafee",numstr));
892 a.push_back(obj);
893 }
894 }
895 }
896 result.push_back(Pair("registered",a));
897 }
898 }
899 return(result);
900}
901
902UniValue OraclesList()
903{
904 UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65];
905 cp = CCinit(&C,EVAL_ORACLES);
906 SetCCtxids(addressIndex,cp->normaladdr);
907 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
908 {
909 txid = it->first.txhash;
910 if ( GetTransaction(txid,createtx,hashBlock,false) != 0 )
911 {
cb96789e 912 if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
366625ca 913 {
914 result.push_back(uint256_str(str,txid));
915 }
916 }
917 }
c926780f 918 return(result);
919}
920
This page took 0.288792 seconds and 4 git commands to generate.