]> Git Repo - VerusCoin.git/blob - src/cc/oracles.cpp
Smart transaction improvements and multisig signing / validation fixes, activation...
[VerusCoin.git] / src / cc / oracles.cpp
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"
17 #include <secp256k1.h>
18
19 /*
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  
33  Implementation notes:
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. 
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  
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  
46  The format string is a set of chars with the following meaning:
47   's' -> <256 char string
48   'S' -> <65536 char string
49   'd' -> <256 binary data
50   'D' -> <65536 binary data
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
55   'h' -> 32 byte hash
56  
57  create:
58  vins.*: normal inputs
59  vout.0: txfee tag to oracle normal address
60  vout.1: change, if any
61  vout.n-1: opreturn with name and description and format for data
62  
63  register:
64  vins.*: normal inputs
65  vout.0: txfee tag to normal marker address
66  vout.1: baton CC utxo
67  vout.2: change, if any
68  vout.n-1: opreturn with oracletxid, pubkey and price per data point
69  
70  subscribe:
71  vins.*: normal inputs
72  vout.0: subscription fee to publishers CC address
73  vout.1: change, if any
74  vout.n-1: opreturn with oracletxid, registered provider's pubkey, amount
75  
76  data:
77  vin.0: normal input
78  vin.1: baton CC utxo (most of the time)
79  vin.2+: subscription or data vout.0
80  vout.0: change to publishers CC address
81  vout.1: baton CC utxo
82  vout.2: payment for dataprovider
83  vout.3: change, if any
84  vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
85  
86  data (without payment) this is not needed as publisher can pay themselves!
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
92  vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
93
94 */
95
96 // start of consensus code
97
98
99 CScript EncodeOraclesCreateOpRet(uint8_t funcid,std::string name,std::string description,std::string format)
100 {
101     CScript opret; uint8_t evalcode = EVAL_ORACLES;
102     opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << name << format << description);
103     return(opret);
104 }
105
106 uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format)
107 {
108     std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid;
109     GetOpReturnData(scriptPubKey,vopret);
110     script = (uint8_t *)vopret.data();
111     if ( script[0] == EVAL_ORACLES )
112     {
113         if ( script[1] == 'C' )
114         {
115             if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> name; ss >> format; ss >> description) != 0 )
116             {
117                 return(script[1]);
118             } else fprintf(stderr,"DecodeOraclesCreateOpRet unmarshal error for C\n");
119         }
120     }
121     return(0);
122 }
123
124 CScript 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
131 uint8_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
144 CScript EncodeOraclesData(uint8_t funcid,uint256 oracletxid,uint256 batontxid,CPubKey pk,std::vector <uint8_t>data)
145 {
146     CScript opret; uint8_t evalcode = EVAL_ORACLES;
147     opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << batontxid << pk << data);
148     return(opret);
149 }
150
151 uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data)
152 {
153     std::vector<uint8_t> vopret; uint8_t *script,e,f;
154     GetOpReturnData(scriptPubKey,vopret);
155     script = (uint8_t *)vopret.data();
156     if ( vopret.size() > 1 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> batontxid; ss >> pk; ss >> data) != 0 )
157     {
158         if ( e == EVAL_ORACLES && f == 'D' )
159             return(f);
160     }
161     return(0);
162 }
163
164 CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp)
165 {
166     static secp256k1_context *ctx;
167     size_t clen = CPubKey::PUBLIC_KEY_SIZE;
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);
171     Myprivkey(priv);
172     cp->evalcode2 = EVAL_ORACLES;
173     for (i=0; i<32; i++)
174         cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]);
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");
180         if ( secp256k1_ec_privkey_tweak_add(ctx,cp->unspendablepriv2,priv) != 0 )
181             break;
182     }
183     if ( secp256k1_ec_pubkey_create(ctx,&pubkey,cp->unspendablepriv2) != 0 )
184     {
185         secp256k1_ec_pubkey_serialize(ctx,(unsigned char*)batonpk.begin(),&clen,&pubkey,SECP256K1_EC_COMPRESSED);
186         cp->unspendablepk2 = batonpk;
187         Getscriptaddress(batonaddr,MakeCC1vout(cp->evalcode,0,batonpk).scriptPubKey);
188         //fprintf(stderr,"batonpk.(%s) -> %s\n",(char *)HexStr(batonpk).c_str(),batonaddr);
189         strcpy(cp->unspendableaddr2,batonaddr);
190     } else fprintf(stderr,"error creating pubkey\n");
191     return(batonpk);
192 }
193
194 int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publisher)
195 {
196     uint256 txid,oracletxid,hashBlock; int64_t datafee=0,dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk;
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;
203         height = (int32_t)it->second.blockHeight;
204         if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
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;
214                         if ( 0 && dheight != 0 )
215                             fprintf(stderr,"set datafee %.8f height.%d\n",(double)datafee/COIN,height);
216                     }
217                 }
218             }
219         }
220     }
221     return(datafee);
222 }
223
224 int64_t OracleDatafee(CScript &scriptPubKey,uint256 oracletxid,CPubKey publisher)
225 {
226     CTransaction oracletx; char markeraddr[64]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0;
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         {
231             CCtxidaddr(markeraddr,oracletxid);
232             datafee = OracleCurrentDatafee(oracletxid,markeraddr,publisher);
233         }
234     }
235     return(datafee);
236 }
237
238 static 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         {
245             const uint256 &txid = tx.GetHash();
246             //char str[65]; fprintf(stderr,"found baton spent in mempool %s\n",uint256_str(str,txid));
247             return(txid);
248         }
249     }
250     return(batontxid);
251 }
252
253 uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 reforacletxid,char *batonaddr,CPubKey publisher,std::vector <uint8_t> &dataarg)
254 {
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;
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;
262         height = (int32_t)it->second.blockHeight;
263         if ( it->second.satoshis != txfee )
264         {
265             fprintf(stderr,"it->second.satoshis %llu != %llu txfee\n",(long long)it->second.satoshis,(long long)txfee);
266             continue;
267         }
268         if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
269         {
270             GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
271             if ( vopret.size() > 2 )
272             {
273                 ptr = (uint8_t *)vopret.data();
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') )
275                 {
276                     if ( oracletxid == reforacletxid && pk == publisher )
277                     {
278                         if ( height > dheight )
279                         {
280                             dheight = height;
281                             batontxid = txid;
282                             if ( ptr[1] == 'D' )
283                                 dataarg = data;
284                             //char str[65]; fprintf(stderr,"set batontxid %s height.%d\n",uint256_str(str,batontxid),height);
285                         }
286                     }
287                 }
288             }
289         }
290     }
291     while ( myIsutxo_spentinmempool(batontxid,1) != 0 )
292         batontxid = myIs_baton_spentinmempool(batontxid,1);
293     return(batontxid);
294 }
295
296 uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
297 {
298     std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
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;
300     batontxid = zeroid;
301     cp = CCinit(&C,EVAL_ORACLES);
302     CCtxidaddr(markeraddr,reforacletxid);
303     SetCCunspents(unspentOutputs,markeraddr);
304     //char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk));
305     for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
306     {
307         txid = it->first.txhash;
308         //fprintf(stderr,"check %s\n",uint256_str(str,txid));
309         height = (int32_t)it->second.blockHeight;
310         if ( myGetTransaction(txid,regtx,hash) != 0 )
311         {
312             if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid && pk == refpk )
313             {
314                 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
315                 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
316                 break;
317             }
318         }
319     }
320     return(batontxid);
321 }
322
323 int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen)
324 {
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;
326     *valp = 0;
327     *hashp = zeroid;
328     if ( str != 0 )
329         str[0] = 0;
330     switch ( fmt )
331     {
332         case 's': slen = data[offset++]; break;
333         case 'S': slen = data[offset++]; slen |= ((int32_t)data[offset++] << 8); break;
334         case 'd': dlen = data[offset++]; break;
335         case 'D': dlen = data[offset++]; dlen |= ((int32_t)data[offset++] << 8); break;
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 )
350         {
351             if ( slen < IGUANA_MAXSCRIPTSIZE && offset+slen <= datalen )
352             {
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);
369         }
370     }
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
413 int64_t _correlate_price(int64_t *prices,int32_t n,int64_t price)
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);
425     else return(price);
426 }
427
428 int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
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
444 int64_t OracleCorrelatedPrice(int32_t height,std::vector <int64_t> origprices)
445 {
446     std::vector <int64_t> sorted; int32_t i,n; int64_t *prices,price;
447     if ( (n= origprices.size()) == 1 )
448         return(origprices[0]);
449     std::sort(origprices.begin(), origprices.end());
450     prices = (int64_t *)calloc(n,sizeof(*prices));
451     i = 0;
452     for (std::vector<int64_t>::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
453         prices[i++] = *it;
454     price = correlate_price(height,prices,i);
455     free(prices);
456     return(price);
457 }
458
459 int32_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;
462     for (std::vector<struct oracleprice_info>::iterator it=publishers.begin(); it!=publishers.end(); it++)
463     {
464         if ( pk == it->pk )
465         {
466             flag = 1;
467             if ( height > it->height )
468             {
469                 it->height = height;
470                 it->data = data;
471                 return(height);
472             }
473         }
474     }
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);
483 }
484
485 int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
486 {
487     std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
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;
489     if ( format[0] != 'L' )
490         return(0);
491     cp = CCinit(&C,EVAL_ORACLES);
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;
496         ht = (int32_t)it->second.blockHeight;
497         if ( myGetTransaction(txid,regtx,hash) != 0 )
498         {
499             if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid )
500             {
501                 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
502                 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
503                 if ( batontxid != zeroid && (ht= oracleprice_add(publishers,pk,ht,data,maxheight)) > maxheight )
504                     maxheight = ht;
505             }
506         }
507     }
508     if ( maxheight > 10 )
509     {
510         for (std::vector<struct oracleprice_info>::const_iterator it=publishers.begin(); it!=publishers.end(); it++)
511         {
512             if ( it->height >= maxheight-10 )
513             {
514                 oracle_format(&hash,&price,0,'L',(uint8_t *)it->data.data(),0,(int32_t)it->data.size());
515                 if ( price != 0 )
516                     prices.push_back(price);
517             }
518         }
519         return(OracleCorrelatedPrice(height,prices));
520     }
521     return(0);
522 }
523
524 int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
525 {
526     //char destaddr[64];
527     if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
528     {
529         //if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
530             return(tx.vout[v].nValue);
531     }
532     return(0);
533 }
534
535 bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,uint256 oracletxid,CPubKey publisher,int64_t datafee)
536 {
537     static uint256 zerohash;
538     CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; CScript scriptPubKey;
539     numvins = tx.vin.size();
540     numvouts = tx.vout.size();
541     if ( OracleDatafee(scriptPubKey,oracletxid,publisher) != datafee )
542         return eval->Invalid("mismatched datafee");
543     scriptPubKey = MakeCC1vout(cp->evalcode,0,publisher).scriptPubKey;
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         {
549             if ( i == 0 )
550                 return eval->Invalid("unexpected vin.0 is CC");
551             //fprintf(stderr,"vini.%d check mempool\n",i);
552             else if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
553                 return eval->Invalid("cant find vinTx");
554             else
555             {
556                 //fprintf(stderr,"vini.%d check hash and vout\n",i);
557                 //if ( hashBlock == zerohash )
558                 //    return eval->Invalid("cant Oracles from mempool");
559                 if ( (assetoshis= IsOraclesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
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                 }
566             }
567         }
568         else if ( i != 0 )
569             return eval->Invalid("vin0 not normal");
570      
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 )
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         }
587     }
588     if ( inputs != outputs+datafee )
589     {
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");
592     }
593     else return(true);
594 }
595
596 bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn, bool fulfilled)
597 {
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;
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     {
606         txid = tx.GetHash();
607         GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
608         if ( vopret.size() > 2 )
609         {
610             script = (uint8_t *)vopret.data();
611             switch ( script[1] )
612             {
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                     {
645                         if ( OraclesDataValidate(cp,eval,tx,oracletxid,publisher,tx.vout[2].nValue) != 0 )
646                         {
647                             return(true);
648                         } else return(false);
649                     }
650                     return eval->Invalid("unexpected OraclesValidate 'D' tx invalid");
651                     break;
652             }
653         }
654         return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
655     }
656     return(true);
657 }
658 // end of consensus code
659
660 // helper functions for rpc calls in rpcwallet.cpp
661
662 int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
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;
672         //char str[65]; fprintf(stderr,"oracle check %s/v%d\n",uint256_str(str,txid),vout);
673         if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
674         {
675             // get valid CC payments
676             if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
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;
685             } //else fprintf(stderr,"nValue %.8f or utxo memspent\n",(double)nValue/COIN);
686         } else fprintf(stderr,"couldnt find transaction\n");
687     }
688     return(totalinputs);
689 }
690
691 int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubKey publisher)
692 {
693     char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock,subtxid; CTransaction subtx;
694     std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
695     GetCCaddress(cp,coinaddr,publisher);
696     SetCCtxids(addressIndex,coinaddr);
697     //fprintf(stderr,"scan lifetime of %s\n",coinaddr);
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         {
703             if ( subtx.vout.size() > 0 && DecodeOraclesOpRet(subtx.vout[subtx.vout.size()-1].scriptPubKey,subtxid,pk,num) == 'S' && subtxid == oracletxid && pk == publisher )
704             {
705                 total += subtx.vout[0].nValue;
706             }
707         }
708     }
709     return(total);
710 }
711
712 std::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;
715     cp = CCinit(&C,EVAL_ORACLES);
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     }
721     if ( txfee == 0 )
722         txfee = 10000;
723     mypk = pubkey2pk(Mypubkey());
724     Oraclespk = GetUnspendable(cp,0);
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
733 std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
734 {
735     CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64];
736     cp = CCinit(&C,EVAL_ORACLES);
737     if ( txfee == 0 )
738         txfee = 10000;
739     if ( datafee < txfee )
740     {
741         fprintf(stderr,"datafee must be txfee or more\n");
742         return("");
743     }
744     mypk = pubkey2pk(Mypubkey());
745     batonpk = OracleBatonPk(batonaddr,cp);
746     markerpubkey = CCtxidaddr(markeraddr,oracletxid);
747     if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
748     {
749         mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
750         mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
751         return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,datafee)));
752     }
753     return("");
754 }
755
756 std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount)
757 {
758     CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64];
759     cp = CCinit(&C,EVAL_ORACLES);
760     if ( txfee == 0 )
761         txfee = 10000;
762     mypk = pubkey2pk(Mypubkey());
763     markerpubkey = CCtxidaddr(markeraddr,oracletxid);
764     if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 )
765     {
766         mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher));
767         mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
768         return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('S',oracletxid,mypk,amount)));
769     }
770     return("");
771 }
772
773 std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> data)
774 {
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;
776     cp = CCinit(&C,EVAL_ORACLES);
777     mypk = pubkey2pk(Mypubkey());
778     if ( data.size() > 8192 )
779     {
780         fprintf(stderr,"datasize %d is too big\n",(int32_t)data.size());
781         return("");
782     }
783     if ( (datafee= OracleDatafee(pubKey,oracletxid,mypk)) <= 0 )
784     {
785         fprintf(stderr,"datafee %.8f is illegal\n",(double)datafee/COIN);
786         return("");
787     }
788     if ( txfee == 0 )
789         txfee = 10000;
790     GetCCaddress(cp,coinaddr,mypk);
791     if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) // have enough funds even if baton utxo not there
792     {
793         batonpk = OracleBatonPk(batonaddr,cp);
794         batontxid = OracleBatonUtxo(txfee,cp,oracletxid,batonaddr,mypk,prevdata);
795         if ( batontxid != zeroid ) // not impossible to fail, but hopefully a very rare event
796             mtx.vin.push_back(CTxIn(batontxid,1,CScript()));
797         else fprintf(stderr,"warning: couldnt find baton utxo %s\n",batonaddr);
798         if ( (inputs= AddOracleInputs(cp,mtx,mypk,datafee,60)) > 0 )
799         {
800             if ( inputs > datafee )
801                 CCchange = (inputs - datafee);
802             mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
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)));
806         } else fprintf(stderr,"couldnt find enough oracle inputs, limit 1 per utxo\n");
807     } else fprintf(stderr,"couldnt add normal inputs\n");
808     return("");
809 }
810
811 UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatlen)
812 {
813     UniValue obj(UniValue::VARR); uint256 hash; int32_t i,j=0; int64_t val; char str[IGUANA_MAXSCRIPTSIZE*2+1];
814     for (i=0; i<formatlen && j<datalen; i++)
815     {
816         str[0] = 0;
817         j = oracle_format(&hash,&val,str,format[i],data,j,datalen);
818         if ( j < 0 )
819             break;
820         obj.push_back(str);
821         if ( j >= datalen )
822             break;
823     }
824     return(obj);
825 }
826
827 UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num)
828 {
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;
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 )
840                         formatstr = (char *)"";
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
853 UniValue OracleInfo(uint256 origtxid)
854 {
855     UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ);
856     std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
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;
858     cp = CCinit(&C,EVAL_ORACLES);
859     CCtxidaddr(markeraddr,origtxid);
860     if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
861     {
862         if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
863         {
864             result.push_back(Pair("result","success"));
865             result.push_back(Pair("txid",uint256_str(str,origtxid)));
866             result.push_back(Pair("name",name));
867             result.push_back(Pair("description",description));
868             result.push_back(Pair("format",format));
869             result.push_back(Pair("marker",markeraddr));
870             SetCCunspents(unspentOutputs,markeraddr);
871             for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
872             {
873                 txid = it->first.txhash;
874                 if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
875                 {
876                     if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
877                     {
878                         obj.push_back(Pair("publisher",pubkey33_str(str,(uint8_t *)pk.begin())));
879                         Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
880                         batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
881                         obj.push_back(Pair("baton",batonaddr));
882                         obj.push_back(Pair("batontxid",uint256_str(str,batontxid)));
883                         funding = LifetimeOraclesFunds(cp,oracletxid,pk);
884                         sprintf(numstr,"%.8f",(double)funding/COIN);
885                         obj.push_back(Pair("lifetime",numstr));
886                         funding = AddOracleInputs(cp,mtx,pk,0,0);
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
901 UniValue 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         {
911             if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
912             {
913                 result.push_back(uint256_str(str,txid));
914             }
915         }
916     }
917     return(result);
918 }
919
This page took 0.075684 seconds and 4 git commands to generate.