1 /******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
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. *
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 *
12 * Removal or modification of this copyright notice is prohibited. *
14 ******************************************************************************/
16 #include "CCOracles.h"
17 #include <secp256k1.h>
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
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
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:
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.
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.
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.
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
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
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
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
65 vout.0: txfee tag to normal marker address
67 vout.2: change, if any
68 vout.n-1: opreturn with oracletxid, pubkey and price per data point
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
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
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
86 data (without payment) this is not needed as publisher can pay themselves!
89 vout.0: txfee to publishers normal address
91 vout.2: change, if any
92 vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
96 // start of consensus code
99 CScript EncodeOraclesCreateOpRet(uint8_t funcid,std::string name,std::string description,std::string format)
101 CScript opret; uint8_t evalcode = EVAL_ORACLES;
102 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << name << format << description);
106 uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format)
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 )
113 if ( script[1] == 'C' )
115 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> name; ss >> format; ss >> description) != 0 )
118 } else fprintf(stderr,"DecodeOraclesCreateOpRet unmarshal error for C\n");
124 CScript EncodeOraclesOpRet(uint8_t funcid,uint256 oracletxid,CPubKey pk,int64_t num)
126 CScript opret; uint8_t evalcode = EVAL_ORACLES;
127 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << pk << num);
131 uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num)
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 )
138 if ( e == EVAL_ORACLES && (f == 'R' || f == 'S') )
144 CScript EncodeOraclesData(uint8_t funcid,uint256 oracletxid,uint256 batontxid,CPubKey pk,std::vector <uint8_t>data)
146 CScript opret; uint8_t evalcode = EVAL_ORACLES;
147 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << batontxid << pk << data);
151 uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data)
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 )
158 if ( e == EVAL_ORACLES && f == 'D' )
164 CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp)
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;
170 ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
172 cp->evalcode2 = EVAL_ORACLES;
174 cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]);
175 while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 )
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 )
183 if ( secp256k1_ec_pubkey_create(ctx,&pubkey,cp->unspendablepriv2) != 0 )
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");
194 int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publisher)
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++)
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 )
206 if ( DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,pk,dfee) == 'R' )
208 if ( oracletxid == reforacletxid && pk == publisher )
210 if ( height > dheight || (height == dheight && dfee < datafee) )
214 if ( 0 && dheight != 0 )
215 fprintf(stderr,"set datafee %.8f height.%d\n",(double)datafee/COIN,height);
224 int64_t OracleDatafee(CScript &scriptPubKey,uint256 oracletxid,CPubKey publisher)
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 )
229 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
231 CCtxidaddr(markeraddr,oracletxid);
232 datafee = OracleCurrentDatafee(oracletxid,markeraddr,publisher);
238 static uint256 myIs_baton_spentinmempool(uint256 batontxid,int32_t batonvout)
240 BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
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 )
245 const uint256 &txid = tx.GetHash();
246 //char str[65]; fprintf(stderr,"found baton spent in mempool %s\n",uint256_str(str,txid));
253 uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 reforacletxid,char *batonaddr,CPubKey publisher,std::vector <uint8_t> &dataarg)
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++)
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 )
265 fprintf(stderr,"it->second.satoshis %llu != %llu txfee\n",(long long)it->second.satoshis,(long long)txfee);
268 if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
270 GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
271 if ( vopret.size() > 2 )
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') )
276 if ( oracletxid == reforacletxid && pk == publisher )
278 if ( height > dheight )
284 //char str[65]; fprintf(stderr,"set batontxid %s height.%d\n",uint256_str(str,batontxid),height);
291 while ( myIsutxo_spentinmempool(batontxid,1) != 0 )
292 batontxid = myIs_baton_spentinmempool(batontxid,1);
296 uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
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;
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++)
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 )
312 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid && pk == refpk )
314 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
315 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
323 int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen)
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;
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;
351 if ( slen < IGUANA_MAXSCRIPTSIZE && offset+slen <= datalen )
353 for (i=0; i<slen; i++)
354 str[i] = data[offset++];
359 else if ( dlen != 0 )
363 if ( dlen < IGUANA_MAXSCRIPTSIZE && offset+dlen <= datalen )
365 for (i=0; i<dlen; i++)
366 sprintf(&str[i<<1],"%02x",data[offset++]);
371 else if ( len != 0 && len+offset <= datalen )
375 iguana_rwbignum(0,&data[offset],len,(uint8_t *)hashp);
377 sprintf(str,"%s",uint256_str(_str,*hashp));
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;
391 sprintf(str,"%lld",(long long)val);
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;
404 sprintf(str,"%llu",(long long)uval);
405 *valp = (int64_t)uval;
413 int64_t _correlate_price(int64_t *prices,int32_t n,int64_t price)
415 int32_t i,count = 0; int64_t diff,threshold = (price >> 8);
418 if ( (diff= (price - prices[i])) < 0 )
420 if ( diff <= threshold )
423 if ( count < (n >> 1) )
428 int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
430 int32_t i,j; int64_t price = 0;
435 j = (height + i) % n;
436 if ( prices[j] != 0 && (price= _correlate_price(prices,n,prices[j])) != 0 )
440 fprintf(stderr,"%llu ",(long long)prices[i]);
441 fprintf(stderr,"-> %llu ht.%d\n",(long long)price,height);
444 int64_t OracleCorrelatedPrice(int32_t height,std::vector <int64_t> origprices)
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));
452 for (std::vector<int64_t>::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
454 price = correlate_price(height,prices,i);
459 int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey pk,int32_t height,std::vector <uint8_t> data,int32_t maxheight)
461 struct oracleprice_info item; int32_t flag = 0;
462 for (std::vector<struct oracleprice_info>::iterator it=publishers.begin(); it!=publishers.end(); it++)
467 if ( height > it->height )
479 item.height = height;
480 publishers.push_back(item);
485 int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
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' )
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++)
495 txid = it->first.txhash;
496 ht = (int32_t)it->second.blockHeight;
497 if ( myGetTransaction(txid,regtx,hash) != 0 )
499 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid )
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 )
508 if ( maxheight > 10 )
510 for (std::vector<struct oracleprice_info>::const_iterator it=publishers.begin(); it!=publishers.end(); it++)
512 if ( it->height >= maxheight-10 )
514 oracle_format(&hash,&price,0,'L',(uint8_t *)it->data.data(),0,(int32_t)it->data.size());
516 prices.push_back(price);
519 return(OracleCorrelatedPrice(height,prices));
524 int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
527 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
529 //if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
530 return(tx.vout[v].nValue);
535 bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,uint256 oracletxid,CPubKey publisher,int64_t datafee)
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++)
546 //fprintf(stderr,"vini.%d\n",i);
547 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 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");
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 )
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;
569 return eval->Invalid("vin0 not normal");
572 for (i=0; i<numvouts; i++)
574 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
575 if ( (assetoshis= IsOraclesvout(cp,tx,i)) != 0 )
581 if ( tx.vout[0].scriptPubKey == scriptPubKey )
582 outputs += assetoshis;
583 else return eval->Invalid("invalid CC vout CC destination");
588 if ( inputs != outputs+datafee )
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");
596 bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn, bool fulfilled)
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;
603 return eval->Invalid("no vouts");
607 GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
608 if ( vopret.size() > 2 )
610 script = (uint8_t *)vopret.data();
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");
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");
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");
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' )
645 if ( OraclesDataValidate(cp,eval,tx,oracletxid,publisher,tx.vout[2].nValue) != 0 )
648 } else return(false);
650 return eval->Invalid("unexpected OraclesValidate 'D' tx invalid");
654 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
658 // end of consensus code
660 // helper functions for rpc calls in rpcwallet.cpp
662 int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
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++)
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 )
675 // get valid CC payments
676 if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
678 if ( total != 0 && maxinputs != 0 )
679 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
680 nValue = it->second.satoshis;
681 totalinputs += nValue;
683 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
685 } //else fprintf(stderr,"nValue %.8f or utxo memspent\n",(double)nValue/COIN);
686 } else fprintf(stderr,"couldnt find transaction\n");
691 int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubKey publisher)
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++)
700 txid = it->first.txhash;
701 if ( GetTransaction(txid,subtx,hashBlock,false) != 0 )
703 if ( subtx.vout.size() > 0 && DecodeOraclesOpRet(subtx.vout[subtx.vout.size()-1].scriptPubKey,subtxid,pk,num) == 'S' && subtxid == oracletxid && pk == publisher )
705 total += subtx.vout[0].nValue;
712 std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format)
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 )
718 fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
723 mypk = pubkey2pk(Mypubkey());
724 Oraclespk = GetUnspendable(cp,0);
725 if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
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)));
733 std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
735 CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64];
736 cp = CCinit(&C,EVAL_ORACLES);
739 if ( datafee < txfee )
741 fprintf(stderr,"datafee must be txfee or more\n");
744 mypk = pubkey2pk(Mypubkey());
745 batonpk = OracleBatonPk(batonaddr,cp);
746 markerpubkey = CCtxidaddr(markeraddr,oracletxid);
747 if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
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)));
756 std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount)
758 CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64];
759 cp = CCinit(&C,EVAL_ORACLES);
762 mypk = pubkey2pk(Mypubkey());
763 markerpubkey = CCtxidaddr(markeraddr,oracletxid);
764 if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 )
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)));
773 std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> data)
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 )
780 fprintf(stderr,"datasize %d is too big\n",(int32_t)data.size());
783 if ( (datafee= OracleDatafee(pubKey,oracletxid,mypk)) <= 0 )
785 fprintf(stderr,"datafee %.8f is illegal\n",(double)datafee/COIN);
790 GetCCaddress(cp,coinaddr,mypk);
791 if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) // have enough funds even if baton utxo not there
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 )
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");
811 UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatlen)
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++)
817 j = oracle_format(&hash,&val,str,format[i],data,j,datalen);
827 UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num)
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 )
833 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
835 while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 )
837 if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid )
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()));
849 result.push_back(Pair("samples",a));
853 UniValue OracleInfo(uint256 origtxid)
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 )
862 if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
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++)
873 txid = it->first.txhash;
874 if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
876 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
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));
895 result.push_back(Pair("registered",a));
901 UniValue OraclesList()
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++)
908 txid = it->first.txhash;
909 if ( GetTransaction(txid,createtx,hashBlock,false) != 0 )
911 if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
913 result.push_back(uint256_str(str,txid));