]> Git Repo - VerusCoin.git/blame - src/cc/oracles.cpp
Test
[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);
442}
443
d5f527a7 444int64_t OracleCorrelatedPrice(int32_t height,std::vector <int64_t> origprices)
059f7e44 445{
6b078fa6 446 std::vector <int64_t> sorted; int32_t i,n; int64_t *prices,price;
447 if ( (n= origprices.size()) == 1 )
448 return(origprices[0]);
a912c7e8 449 std::sort(origprices.begin(), origprices.end());
450 prices = (int64_t *)calloc(n,sizeof(*prices));
6b078fa6 451 i = 0;
452 for (std::vector<int64_t>::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
a912c7e8 453 prices[i++] = *it;
d5f527a7 454 price = correlate_price(height,prices,i);
6b078fa6 455 free(prices);
456 return(price);
457}
458
459int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey pk,int32_t height,std::vector <uint8_t> data,int32_t maxheight)
460{
461 struct oracleprice_info item; int32_t flag = 0;
bedac1d5 462 for (std::vector<struct oracleprice_info>::iterator it=publishers.begin(); it!=publishers.end(); it++)
059f7e44 463 {
a5faf9e9 464 if ( pk == it->pk )
059f7e44 465 {
6b078fa6 466 flag = 1;
a912c7e8 467 if ( height > it->height )
6b078fa6 468 {
a5faf9e9 469 it->height = height;
470 it->data = data;
6b078fa6 471 return(height);
472 }
059f7e44 473 }
474 }
6b078fa6 475 if ( flag == 0 )
476 {
477 item.pk = pk;
478 item.data = data;
479 item.height = height;
480 publishers.push_back(item);
481 return(height);
482 } else return(0);
059f7e44 483}
484
485int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
486{
487 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
3515c101 488 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 489 if ( format[0] != 'L' )
490 return(0);
d898dbce 491 cp = CCinit(&C,EVAL_ORACLES);
059f7e44 492 SetCCunspents(unspentOutputs,markeraddr);
493 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
494 {
495 txid = it->first.txhash;
a912c7e8 496 ht = (int32_t)it->second.blockHeight;
6b078fa6 497 if ( myGetTransaction(txid,regtx,hash) != 0 )
059f7e44 498 {
c6636cf0 499 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid )
059f7e44 500 {
6b078fa6 501 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
502 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
a912c7e8 503 if ( batontxid != zeroid && (ht= oracleprice_add(publishers,pk,ht,data,maxheight)) > maxheight )
6b078fa6 504 maxheight = ht;
059f7e44 505 }
506 }
507 }
6b078fa6 508 if ( maxheight > 10 )
509 {
510 for (std::vector<struct oracleprice_info>::const_iterator it=publishers.begin(); it!=publishers.end(); it++)
511 {
a5faf9e9 512 if ( it->height >= maxheight-10 )
6b078fa6 513 {
a5faf9e9 514 oracle_format(&hash,&price,0,'L',(uint8_t *)it->data.data(),0,(int32_t)it->data.size());
6b078fa6 515 if ( price != 0 )
516 prices.push_back(price);
517 }
518 }
a912c7e8 519 return(OracleCorrelatedPrice(height,prices));
6b078fa6 520 }
521 return(0);
26ca942e 522}
523
c926780f 524int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
525{
4b19e190 526 //char destaddr[64];
c926780f 527 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
528 {
4b19e190 529 //if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
c926780f 530 return(tx.vout[v].nValue);
531 }
532 return(0);
533}
534
26ac5473 535bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,uint256 oracletxid,CPubKey publisher,int64_t datafee)
c926780f 536{
537 static uint256 zerohash;
4d55981c 538 CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; CScript scriptPubKey;
c926780f 539 numvins = tx.vin.size();
540 numvouts = tx.vout.size();
4d55981c 541 if ( OracleDatafee(scriptPubKey,oracletxid,publisher) != datafee )
542 return eval->Invalid("mismatched datafee");
543 scriptPubKey = MakeCC1vout(cp->evalcode,0,publisher).scriptPubKey;
c926780f 544 for (i=0; i<numvins; i++)
545 {
546 //fprintf(stderr,"vini.%d\n",i);
547 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
548 {
545c8190 549 if ( i == 0 )
550 return eval->Invalid("unexpected vin.0 is CC");
c926780f 551 //fprintf(stderr,"vini.%d check mempool\n",i);
545c8190 552 else if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
c926780f 553 return eval->Invalid("cant find vinTx");
554 else
555 {
556 //fprintf(stderr,"vini.%d check hash and vout\n",i);
b2da43cf 557 //if ( hashBlock == zerohash )
558 // return eval->Invalid("cant Oracles from mempool");
c926780f 559 if ( (assetoshis= IsOraclesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
4d55981c 560 {
561 if ( i == 1 && vinTx.vout[1].scriptPubKey != tx.vout[1].scriptPubKey )
562 return eval->Invalid("baton violation");
563 else if ( i != 1 && scriptPubKey == vinTx.vout[tx.vin[i].prevout.n].scriptPubKey )
564 inputs += assetoshis;
565 }
c926780f 566 }
567 }
545c8190 568 else if ( i != 0 )
569 return eval->Invalid("vin0 not normal");
570
c926780f 571 }
572 for (i=0; i<numvouts; i++)
573 {
574 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
575 if ( (assetoshis= IsOraclesvout(cp,tx,i)) != 0 )
545c8190 576 {
577 if ( i < 2 )
578 {
579 if ( i == 0 )
580 {
581 if ( tx.vout[0].scriptPubKey == scriptPubKey )
582 outputs += assetoshis;
583 else return eval->Invalid("invalid CC vout CC destination");
584 }
585 }
586 }
c926780f 587 }
26ac5473 588 if ( inputs != outputs+datafee )
c926780f 589 {
26ac5473 590 fprintf(stderr,"inputs %llu vs outputs %llu + datafee %llu\n",(long long)inputs,(long long)outputs,(long long)datafee);
591 return eval->Invalid("mismatched inputs != outputs + datafee");
c926780f 592 }
593 else return(true);
594}
595
596bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
597{
4d55981c 598 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 599 numvins = tx.vin.size();
600 numvouts = tx.vout.size();
601 preventCCvins = preventCCvouts = -1;
602 if ( numvouts < 1 )
603 return eval->Invalid("no vouts");
604 else
605 {
4d55981c 606 txid = tx.GetHash();
607 GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
835333f2 608 if ( vopret.size() > 2 )
c926780f 609 {
4d55981c 610 script = (uint8_t *)vopret.data();
611 switch ( script[1] )
c926780f 612 {
4d55981c 613 case 'C': // create
614 // vins.*: normal inputs
615 // vout.0: txfee tag to oracle normal address
616 // vout.1: change, if any
617 // vout.n-1: opreturn with name and description and format for data
618 return eval->Invalid("unexpected OraclesValidate for create");
619 break;
620 case 'R': // register
621 // vins.*: normal inputs
622 // vout.0: txfee tag to normal marker address
623 // vout.1: baton CC utxo
624 // vout.2: change, if any
625 // vout.n-1: opreturn with createtxid, pubkey and price per data point
626 return eval->Invalid("unexpected OraclesValidate for register");
627 break;
628 case 'S': // subscribe
629 // vins.*: normal inputs
630 // vout.0: subscription fee to publishers CC address
631 // vout.1: change, if any
632 // vout.n-1: opreturn with createtxid, registered provider's pubkey, amount
633 return eval->Invalid("unexpected OraclesValidate for subscribe");
634 break;
635 case 'D': // data
636 // vin.0: normal input
637 // vin.1: baton CC utxo (most of the time)
638 // vin.2+: subscription vout.0
639 // vout.0: change to publishers CC address
640 // vout.1: baton CC utxo
641 // vout.2: payment for dataprovider
642 // vout.3: change, if any
643 if ( numvins >= 2 && numvouts >= 3 && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,batontxid,publisher,data) == 'D' )
644 {
26ac5473 645 if ( OraclesDataValidate(cp,eval,tx,oracletxid,publisher,tx.vout[2].nValue) != 0 )
4d55981c 646 {
4d55981c 647 return(true);
545c8190 648 } else return(false);
4d55981c 649 }
650 return eval->Invalid("unexpected OraclesValidate 'D' tx invalid");
651 break;
c926780f 652 }
653 }
4d55981c 654 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
c926780f 655 }
4d55981c 656 return(true);
c926780f 657}
658// end of consensus code
659
660// helper functions for rpc calls in rpcwallet.cpp
661
53314c07 662int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
c926780f 663{
664 char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
665 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
666 GetCCaddress(cp,coinaddr,pk);
667 SetCCunspents(unspentOutputs,coinaddr);
668 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
669 {
670 txid = it->first.txhash;
671 vout = (int32_t)it->first.index;
7fb5e4aa 672 //char str[65]; fprintf(stderr,"oracle check %s/v%d\n",uint256_str(str,txid),vout);
c926780f 673 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
674 {
a2094466 675 // get valid CC payments
4d55981c 676 if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
c926780f 677 {
678 if ( total != 0 && maxinputs != 0 )
679 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
680 nValue = it->second.satoshis;
681 totalinputs += nValue;
682 n++;
683 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
684 break;
5b7e7959 685 } //else fprintf(stderr,"nValue %.8f or utxo memspent\n",(double)nValue/COIN);
4b19e190 686 } else fprintf(stderr,"couldnt find transaction\n");
c926780f 687 }
688 return(totalinputs);
689}
690
718aa08e 691int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubKey publisher)
c926780f 692{
cb96789e 693 char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock,subtxid; CTransaction subtx;
366625ca 694 std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
718aa08e 695 GetCCaddress(cp,coinaddr,publisher);
366625ca 696 SetCCtxids(addressIndex,coinaddr);
9d9ad70f 697 //fprintf(stderr,"scan lifetime of %s\n",coinaddr);
366625ca 698 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
699 {
700 txid = it->first.txhash;
701 if ( GetTransaction(txid,subtx,hashBlock,false) != 0 )
702 {
718aa08e 703 if ( subtx.vout.size() > 0 && DecodeOraclesOpRet(subtx.vout[subtx.vout.size()-1].scriptPubKey,subtxid,pk,num) == 'S' && subtxid == oracletxid && pk == publisher )
366625ca 704 {
705 total += subtx.vout[0].nValue;
706 }
707 }
708 }
709 return(total);
710}
711
712std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format)
713{
714 CMutableTransaction mtx; CPubKey mypk,Oraclespk; struct CCcontract_info *cp,C;
c926780f 715 cp = CCinit(&C,EVAL_ORACLES);
366625ca 716 if ( name.size() > 32 || description.size() > 4096 || format.size() > 4096 )
717 {
718 fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
719 return("");
720 }
c926780f 721 if ( txfee == 0 )
722 txfee = 10000;
366625ca 723 mypk = pubkey2pk(Mypubkey());
c926780f 724 Oraclespk = GetUnspendable(cp,0);
366625ca 725 if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
726 {
727 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(Oraclespk)) << OP_CHECKSIG));
728 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesCreateOpRet('C',name,description,format)));
729 }
730 return("");
731}
732
733std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
734{
612f676a 735 CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64];
366625ca 736 cp = CCinit(&C,EVAL_ORACLES);
366625ca 737 if ( txfee == 0 )
738 txfee = 10000;
059f7e44 739 if ( datafee < txfee )
740 {
741 fprintf(stderr,"datafee must be txfee or more\n");
742 return("");
743 }
c926780f 744 mypk = pubkey2pk(Mypubkey());
7af451d0 745 batonpk = OracleBatonPk(batonaddr,cp);
612f676a 746 markerpubkey = CCtxidaddr(markeraddr,oracletxid);
26ca942e 747 if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
366625ca 748 {
ae846fcc 749 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
26ca942e 750 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
366625ca 751 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,datafee)));
752 }
753 return("");
754}
755
756std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount)
757{
612f676a 758 CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64];
366625ca 759 cp = CCinit(&C,EVAL_ORACLES);
366625ca 760 if ( txfee == 0 )
761 txfee = 10000;
762 mypk = pubkey2pk(Mypubkey());
612f676a 763 markerpubkey = CCtxidaddr(markeraddr,oracletxid);
366625ca 764 if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 )
765 {
766 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher));
ae846fcc 767 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
cb96789e 768 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('S',oracletxid,mypk,amount)));
366625ca 769 }
c926780f 770 return("");
771}
772
366625ca 773std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> data)
c926780f 774{
059f7e44 775 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 776 cp = CCinit(&C,EVAL_ORACLES);
cb96789e 777 mypk = pubkey2pk(Mypubkey());
366625ca 778 if ( data.size() > 8192 )
779 {
780 fprintf(stderr,"datasize %d is too big\n",(int32_t)data.size());
781 return("");
782 }
a2094466 783 if ( (datafee= OracleDatafee(pubKey,oracletxid,mypk)) <= 0 )
366625ca 784 {
785 fprintf(stderr,"datafee %.8f is illegal\n",(double)datafee/COIN);
786 return("");
787 }
c926780f 788 if ( txfee == 0 )
789 txfee = 10000;
366625ca 790 GetCCaddress(cp,coinaddr,mypk);
c5c1aaa1 791 if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) // have enough funds even if baton utxo not there
c926780f 792 {
7af451d0 793 batonpk = OracleBatonPk(batonaddr,cp);
059f7e44 794 batontxid = OracleBatonUtxo(txfee,cp,oracletxid,batonaddr,mypk,prevdata);
26ca942e 795 if ( batontxid != zeroid ) // not impossible to fail, but hopefully a very rare event
796 mtx.vin.push_back(CTxIn(batontxid,1,CScript()));
718aa08e 797 else fprintf(stderr,"warning: couldnt find baton utxo %s\n",batonaddr);
4b19e190 798 if ( (inputs= AddOracleInputs(cp,mtx,mypk,datafee,60)) > 0 )
366625ca 799 {
800 if ( inputs > datafee )
801 CCchange = (inputs - datafee);
802 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
26ca942e 803 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
804 mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
805 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data)));
4084a149 806 } else fprintf(stderr,"couldnt find enough oracle inputs, limit 1 per utxo\n");
c46ccfc3 807 } else fprintf(stderr,"couldnt add normal inputs\n");
c926780f 808 return("");
809}
810
26ca942e 811UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatlen)
812{
7d6b0f58 813 UniValue obj(UniValue::VARR); uint256 hash; int32_t i,j=0; int64_t val; char str[IGUANA_MAXSCRIPTSIZE*2+1];
26ca942e 814 for (i=0; i<formatlen && j<datalen; i++)
815 {
816 str[0] = 0;
059f7e44 817 j = oracle_format(&hash,&val,str,format[i],data,j,datalen);
26ca942e 818 if ( j < 0 )
819 break;
820 obj.push_back(str);
821 if ( j >= datalen )
822 break;
823 }
824 return(obj);
825}
826
827UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num)
828{
760ff4b8 829 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 830 result.push_back(Pair("result","success"));
831 if ( GetTransaction(reforacletxid,oracletx,hashBlock,false) != 0 && (numvouts=oracletx.vout.size()) > 0 )
832 {
833 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
834 {
835 while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 )
836 {
837 if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid )
838 {
839 if ( (formatstr= (char *)format.c_str()) == 0 )
3fd708a6 840 formatstr = (char *)"";
26ca942e 841 a.push_back(OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()));
842 batontxid = btxid;
843 if ( ++n >= num )
844 break;
845 } else break;
846 }
847 }
848 }
849 result.push_back(Pair("samples",a));
850 return(result);
851}
852
366625ca 853UniValue OracleInfo(uint256 origtxid)
c926780f 854{
26ca942e 855 UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ);
856 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
612f676a 857 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 858 cp = CCinit(&C,EVAL_ORACLES);
612f676a 859 CCtxidaddr(markeraddr,origtxid);
fb6f9ce9 860 if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
366625ca 861 {
fb6f9ce9 862 if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
366625ca 863 {
26ca942e 864 result.push_back(Pair("result","success"));
366625ca 865 result.push_back(Pair("txid",uint256_str(str,origtxid)));
866 result.push_back(Pair("name",name));
867 result.push_back(Pair("description",description));
26ca942e 868 result.push_back(Pair("format",format));
366625ca 869 result.push_back(Pair("marker",markeraddr));
26ca942e 870 SetCCunspents(unspentOutputs,markeraddr);
871 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
366625ca 872 {
873 txid = it->first.txhash;
874 if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
875 {
fb6f9ce9 876 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
366625ca 877 {
17a9434a 878 obj.push_back(Pair("publisher",pubkey33_str(str,(uint8_t *)pk.begin())));
26ca942e 879 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
059f7e44 880 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
26ca942e 881 obj.push_back(Pair("baton",batonaddr));
882 obj.push_back(Pair("batontxid",uint256_str(str,batontxid)));
366625ca 883 funding = LifetimeOraclesFunds(cp,oracletxid,pk);
884 sprintf(numstr,"%.8f",(double)funding/COIN);
885 obj.push_back(Pair("lifetime",numstr));
53314c07 886 funding = AddOracleInputs(cp,mtx,pk,0,0);
366625ca 887 sprintf(numstr,"%.8f",(double)funding/COIN);
888 obj.push_back(Pair("funds",numstr));
889 sprintf(numstr,"%.8f",(double)datafee/COIN);
890 obj.push_back(Pair("datafee",numstr));
891 a.push_back(obj);
892 }
893 }
894 }
895 result.push_back(Pair("registered",a));
896 }
897 }
898 return(result);
899}
900
901UniValue OraclesList()
902{
903 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];
904 cp = CCinit(&C,EVAL_ORACLES);
905 SetCCtxids(addressIndex,cp->normaladdr);
906 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
907 {
908 txid = it->first.txhash;
909 if ( GetTransaction(txid,createtx,hashBlock,false) != 0 )
910 {
cb96789e 911 if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
366625ca 912 {
913 result.push_back(uint256_str(str,txid));
914 }
915 }
916 }
c926780f 917 return(result);
918}
919
This page took 0.206942 seconds and 4 git commands to generate.