]> Git Repo - VerusCoin.git/blame - src/cc/oracles.cpp
Fix
[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"
17
18/*
366625ca 19 An oracles CC has the purpose of converting offchain data into onchain data
20 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
21
22 That begs the question, "what would an oracles CC do?"
23 A couple of things come to mind, ie. payments to oracles for future offchain data and maybe some sort of dispute/censoring ability
24
25 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.
26 linked to this txid would be two types of transactions:
27 a) oracle providers
28 b) oracle data users
29
30 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.
31
26ca942e 32 Implementation notes:
4d55981c 33 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 34
35 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.
36
37 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
38
366625ca 39 Required transactions:
40 0) create oracle description -> just needs to create txid for oracle data
41 1) register as oracle data provider with price -> become a registered oracle data provider
42 2) pay provider for N oracle data points -> lock funds for oracle provider
43 3) publish oracle data point -> publish data and collect payment
44
a8c35575 45 The format string is a set of chars with the following meaning:
46 's' -> <256 char string
47 'S' -> <65536 char string
48 'c' -> 1 byte signed little endian number, 'C' unsigned
49 't' -> 2 byte signed little endian number, 'T' unsigned
50 'i' -> 4 byte signed little endian number, 'I' unsigned
51 'l' -> 8 byte signed little endian number, 'L' unsigned
52 uppercase is unsigned, lowercase is a signed number
53
366625ca 54 create:
55 vins.*: normal inputs
56 vout.0: txfee tag to oracle normal address
71d6c154 57 vout.1: change, if any
58 vout.n-1: opreturn with name and description and format for data
366625ca 59
60 register:
61 vins.*: normal inputs
62 vout.0: txfee tag to normal marker address
26ca942e 63 vout.1: baton CC utxo
64 vout.2: change, if any
4d55981c 65 vout.n-1: opreturn with oracletxid, pubkey and price per data point
366625ca 66
67 subscribe:
68 vins.*: normal inputs
69 vout.0: subscription fee to publishers CC address
71d6c154 70 vout.1: change, if any
4d55981c 71 vout.n-1: opreturn with oracletxid, registered provider's pubkey, amount
366625ca 72
73 data:
74 vin.0: normal input
26ca942e 75 vin.1: baton CC utxo (most of the time)
4d55981c 76 vin.2+: subscription or data vout.0
366625ca 77 vout.0: change to publishers CC address
26ca942e 78 vout.1: baton CC utxo
79 vout.2: payment for dataprovider
80 vout.3: change, if any
4d55981c 81 vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
6ea86373 82
4d55981c 83 data (without payment) this is not needed as publisher can pay themselves!
26ca942e 84 vin.0: normal input
85 vin.1: baton CC utxo
86 vout.0: txfee to publishers normal address
87 vout.1: baton CC utxo
88 vout.2: change, if any
4d55981c 89 vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
26ca942e 90
c926780f 91*/
92
93// start of consensus code
94
cb96789e 95
96CScript EncodeOraclesCreateOpRet(uint8_t funcid,std::string name,std::string description,std::string format)
97{
98 CScript opret; uint8_t evalcode = EVAL_ORACLES;
99 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << name << description << format);
100 return(opret);
101}
102
103uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format)
104{
5a53af78 105 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid;
cb96789e 106 GetOpReturnData(scriptPubKey,vopret);
107 script = (uint8_t *)vopret.data();
108 if ( script[0] == EVAL_ORACLES )
109 {
110 if ( script[1] == 'C' )
111 {
112 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> name; ss >> description; ss >> format) != 0 )
113 {
114 return(script[1]);
115 } else fprintf(stderr,"DecodeOraclesCreateOpRet unmarshal error for C\n");
116 }
117 }
118 return(0);
119}
120
121CScript EncodeOraclesOpRet(uint8_t funcid,uint256 oracletxid,CPubKey pk,int64_t num)
122{
123 CScript opret; uint8_t evalcode = EVAL_ORACLES;
124 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << pk << num);
125 return(opret);
126}
127
128uint8_t DecodeOraclesOpRet(const CScript &scriptPubKey,uint256 &oracletxid,CPubKey &pk,int64_t &num)
129{
130 std::vector<uint8_t> vopret; uint8_t *script,e,f;
131 GetOpReturnData(scriptPubKey,vopret);
132 script = (uint8_t *)vopret.data();
133 if ( vopret.size() > 1 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> pk; ss >> num) != 0 )
134 {
135 if ( e == EVAL_ORACLES && (f == 'R' || f == 'S') )
136 return(f);
137 }
138 return(0);
139}
140
26ca942e 141CScript EncodeOraclesData(uint8_t funcid,uint256 oracletxid,uint256 batontxid,CPubKey pk,std::vector <uint8_t>data)
cb96789e 142{
143 CScript opret; uint8_t evalcode = EVAL_ORACLES;
26ca942e 144 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << oracletxid << batontxid << pk << data);
cb96789e 145 return(opret);
146}
147
26ca942e 148uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data)
cb96789e 149{
150 std::vector<uint8_t> vopret; uint8_t *script,e,f;
151 GetOpReturnData(scriptPubKey,vopret);
152 script = (uint8_t *)vopret.data();
26ca942e 153 if ( vopret.size() > 1 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> oracletxid; ss >> batontxid; ss >> pk; ss >> data) != 0 )
cb96789e 154 {
155 if ( e == EVAL_ORACLES && f == 'D' )
156 return(f);
157 }
158 return(0);
159}
160
26ca942e 161CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp,CPubKey mypk)
162{
163 CPubKey batonpk; CKey key; std::vector<unsigned char> vchTmp; uint8_t *ptr,priv[32]; int32_t i;
164 Myprivkey(priv);
165 vchTmp.resize(32);
166 ptr = vchTmp.data();
167 for (i=0; i<32; i++)
168 {
169 ptr[i] = (priv[i] ^ cp->CCpriv[i]);
170 cp->unspendablepriv2[i] = ptr[i];
171 }
172 CPrivKey vchPrivKey(vchTmp.begin(), vchTmp.end());
173 if (!key.SetPrivKey(vchPrivKey, false))
174 {
175 printf("ThreadSendAlert() : key.SetPrivKey failed\n");
a3532c80 176 return(batonpk);
26ca942e 177 }
178 batonpk = cp->unspendablepk2 = key.GetPubKey();
179 Getscriptaddress(batonaddr,CScript() << ParseHex(HexStr(batonpk)) << OP_CHECKSIG);
180 strcpy(cp->unspendableaddr2,batonaddr);
181 return(batonpk);
182}
183
184int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publisher)
185{
a3532c80 186 uint256 txid,oracletxid,hashBlock; int64_t datafee=0,dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk;
26ca942e 187 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
188 SetCCunspents(unspentOutputs,markeraddr);
189 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
190 {
191 txid = it->first.txhash;
192 vout = (int32_t)it->first.index;
a3532c80 193 height = (int32_t)it->second.blockHeight;
26ca942e 194 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
195 {
196 if ( DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,pk,dfee) == 'R' )
197 {
198 if ( oracletxid == reforacletxid && pk == publisher )
199 {
200 if ( height > dheight || (height == dheight && dfee < datafee) )
201 {
202 dheight = height;
203 datafee = dfee;
204 fprintf(stderr,"set datafee %.8f height.%d\n",(double)datafee/COIN,height);
205 }
206 }
207 }
208 }
209 }
210 return(datafee);
211}
212
213uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 reforacletxid,char *batonaddr,CPubKey publisher)
214{
3fd708a6 215 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 216 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
217 SetCCunspents(unspentOutputs,batonaddr);
218 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
219 {
220 txid = it->first.txhash;
221 vout = (int32_t)it->first.index;
a3532c80 222 height = (int32_t)it->second.blockHeight;
26ca942e 223 if ( it->second.satoshis != txfee )
224 continue;
225 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
226 {
a3532c80 227 GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
26ca942e 228 if ( vopret.size() > 2 )
229 {
230 ptr = (uint8_t *)vopret.data();
231 if ( (ptr[1] == 'R' && DecodeOraclesOpRet(tx.vout[numvouts-1].scriptPubKey,oracletxid,pk,dfee) == 'R') || (ptr[1] == 'D' && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D') )
232 {
233 if ( oracletxid == reforacletxid && pk == publisher )
234 {
235 if ( height > dheight )
236 {
237 dheight = height;
238 batontxid = txid;
239 char str[65]; fprintf(stderr,"set batontxid %s height.%d\n",uint256_str(str,batontxid),height);
240 }
241 }
242 }
243 }
244 }
245 }
246 return(batontxid);
247}
248
249int64_t OracleDatafee(CScript &scriptPubKey,uint256 oracletxid,CPubKey publisher)
250{
251 CTransaction oracletx; char markeraddr[64]; CPubKey markerpubkey; uint8_t buf33[33]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0;
252 if ( GetTransaction(oracletxid,oracletx,hashBlock,false) != 0 && (numvouts= oracletx.vout.size()) > 0 )
253 {
254 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
255 {
256 buf33[0] = 0x02;
257 endiancpy(&buf33[1],(uint8_t *)&oracletxid,32);
258 markerpubkey = buf2pk(buf33);
259 scriptPubKey = CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG;
260 Getscriptaddress(markeraddr,scriptPubKey);
261 datafee = OracleCurrentDatafee(oracletxid,markeraddr,publisher);
262 }
263 }
264 return(datafee);
265}
266
c926780f 267int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
268{
269 char destaddr[64];
270 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
271 {
272 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
273 return(tx.vout[v].nValue);
274 }
275 return(0);
276}
277
545c8190 278bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,uint256 oracletxid,CPubKey publisher,uint64_t txfee,int64_t datafee)
c926780f 279{
280 static uint256 zerohash;
4d55981c 281 CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; CScript scriptPubKey;
c926780f 282 numvins = tx.vin.size();
283 numvouts = tx.vout.size();
4d55981c 284 if ( OracleDatafee(scriptPubKey,oracletxid,publisher) != datafee )
285 return eval->Invalid("mismatched datafee");
286 scriptPubKey = MakeCC1vout(cp->evalcode,0,publisher).scriptPubKey;
c926780f 287 for (i=0; i<numvins; i++)
288 {
289 //fprintf(stderr,"vini.%d\n",i);
290 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
291 {
545c8190 292 if ( i == 0 )
293 return eval->Invalid("unexpected vin.0 is CC");
c926780f 294 //fprintf(stderr,"vini.%d check mempool\n",i);
545c8190 295 else if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
c926780f 296 return eval->Invalid("cant find vinTx");
297 else
298 {
299 //fprintf(stderr,"vini.%d check hash and vout\n",i);
300 if ( hashBlock == zerohash )
301 return eval->Invalid("cant Oracles from mempool");
302 if ( (assetoshis= IsOraclesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
4d55981c 303 {
304 if ( i == 1 && vinTx.vout[1].scriptPubKey != tx.vout[1].scriptPubKey )
305 return eval->Invalid("baton violation");
306 else if ( i != 1 && scriptPubKey == vinTx.vout[tx.vin[i].prevout.n].scriptPubKey )
307 inputs += assetoshis;
308 }
c926780f 309 }
310 }
545c8190 311 else if ( i != 0 )
312 return eval->Invalid("vin0 not normal");
313
c926780f 314 }
315 for (i=0; i<numvouts; i++)
316 {
317 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
318 if ( (assetoshis= IsOraclesvout(cp,tx,i)) != 0 )
545c8190 319 {
320 if ( i < 2 )
321 {
322 if ( i == 0 )
323 {
324 if ( tx.vout[0].scriptPubKey == scriptPubKey )
325 outputs += assetoshis;
326 else return eval->Invalid("invalid CC vout CC destination");
327 }
328 }
329 }
330 else if ( i < 2 )
331 return eval->Invalid("vout0 or vout1 is normal");
c926780f 332 }
4d55981c 333 if ( inputs != outputs+txfee+datafee )
c926780f 334 {
4d55981c 335 fprintf(stderr,"inputs %llu vs outputs %llu + datafee %llu + txfee %llu\n",(long long)inputs,(long long)outputs,(long long)datafee,(long long)txfee);
336 return eval->Invalid("mismatched inputs != outputs + datafee + txfee");
c926780f 337 }
338 else return(true);
339}
340
341bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
342{
4d55981c 343 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 344 numvins = tx.vin.size();
345 numvouts = tx.vout.size();
346 preventCCvins = preventCCvouts = -1;
347 if ( numvouts < 1 )
348 return eval->Invalid("no vouts");
349 else
350 {
4d55981c 351 txid = tx.GetHash();
352 GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
835333f2 353 if ( vopret.size() > 2 )
c926780f 354 {
4d55981c 355 script = (uint8_t *)vopret.data();
356 switch ( script[1] )
c926780f 357 {
4d55981c 358 case 'C': // create
359 // vins.*: normal inputs
360 // vout.0: txfee tag to oracle normal address
361 // vout.1: change, if any
362 // vout.n-1: opreturn with name and description and format for data
363 return eval->Invalid("unexpected OraclesValidate for create");
364 break;
365 case 'R': // register
366 // vins.*: normal inputs
367 // vout.0: txfee tag to normal marker address
368 // vout.1: baton CC utxo
369 // vout.2: change, if any
370 // vout.n-1: opreturn with createtxid, pubkey and price per data point
371 return eval->Invalid("unexpected OraclesValidate for register");
372 break;
373 case 'S': // subscribe
374 // vins.*: normal inputs
375 // vout.0: subscription fee to publishers CC address
376 // vout.1: change, if any
377 // vout.n-1: opreturn with createtxid, registered provider's pubkey, amount
378 return eval->Invalid("unexpected OraclesValidate for subscribe");
379 break;
380 case 'D': // data
381 // vin.0: normal input
382 // vin.1: baton CC utxo (most of the time)
383 // vin.2+: subscription vout.0
384 // vout.0: change to publishers CC address
385 // vout.1: baton CC utxo
386 // vout.2: payment for dataprovider
387 // vout.3: change, if any
388 if ( numvins >= 2 && numvouts >= 3 && DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,batontxid,publisher,data) == 'D' )
389 {
545c8190 390 if ( OraclesDataValidate(cp,eval,tx,oracletxid,publisher,txfee,tx.vout[2].nValue) != 0 )
4d55981c 391 {
4d55981c 392 return(true);
545c8190 393 } else return(false);
4d55981c 394 }
395 return eval->Invalid("unexpected OraclesValidate 'D' tx invalid");
396 break;
c926780f 397 }
398 }
4d55981c 399 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
c926780f 400 }
4d55981c 401 return(true);
c926780f 402}
403// end of consensus code
404
405// helper functions for rpc calls in rpcwallet.cpp
406
53314c07 407int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
c926780f 408{
409 char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
410 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
411 GetCCaddress(cp,coinaddr,pk);
412 SetCCunspents(unspentOutputs,coinaddr);
413 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
414 {
415 txid = it->first.txhash;
416 vout = (int32_t)it->first.index;
c926780f 417 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
418 {
a2094466 419 // get valid CC payments
4d55981c 420 if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
c926780f 421 {
422 if ( total != 0 && maxinputs != 0 )
423 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
424 nValue = it->second.satoshis;
425 totalinputs += nValue;
426 n++;
427 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
428 break;
429 }
430 }
431 }
432 return(totalinputs);
433}
434
366625ca 435int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubKey regpk)
c926780f 436{
cb96789e 437 char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock,subtxid; CTransaction subtx;
366625ca 438 std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
439 GetCCaddress(cp,coinaddr,regpk);
440 SetCCtxids(addressIndex,coinaddr);
441 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
442 {
443 txid = it->first.txhash;
444 if ( GetTransaction(txid,subtx,hashBlock,false) != 0 )
445 {
446 if ( subtx.vout.size() > 0 && DecodeOraclesOpRet(subtx.vout[subtx.vout.size()-1].scriptPubKey,subtxid,pk,num) == 'S' && subtxid == oracletxid && regpk == pk )
447 {
448 total += subtx.vout[0].nValue;
449 }
450 }
451 }
452 return(total);
453}
454
455std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format)
456{
457 CMutableTransaction mtx; CPubKey mypk,Oraclespk; struct CCcontract_info *cp,C;
c926780f 458 cp = CCinit(&C,EVAL_ORACLES);
366625ca 459 if ( name.size() > 32 || description.size() > 4096 || format.size() > 4096 )
460 {
461 fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
462 return("");
463 }
c926780f 464 if ( txfee == 0 )
465 txfee = 10000;
366625ca 466 mypk = pubkey2pk(Mypubkey());
c926780f 467 Oraclespk = GetUnspendable(cp,0);
366625ca 468 if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
469 {
470 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(Oraclespk)) << OP_CHECKSIG));
471 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesCreateOpRet('C',name,description,format)));
472 }
473 return("");
474}
475
476std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
477{
26ca942e 478 CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; uint8_t buf33[33]; char markeraddr[64],batonaddr[64];
366625ca 479 cp = CCinit(&C,EVAL_ORACLES);
366625ca 480 if ( txfee == 0 )
481 txfee = 10000;
c926780f 482 mypk = pubkey2pk(Mypubkey());
366625ca 483 buf33[0] = 0x02;
5a53af78 484 endiancpy(&buf33[1],(uint8_t *)&oracletxid,32);
366625ca 485 markerpubkey = buf2pk(buf33);
fb6f9ce9 486 Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
26ca942e 487 batonpk = OracleBatonPk(batonaddr,cp,mypk);
488 if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
366625ca 489 {
ae846fcc 490 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
26ca942e 491 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
366625ca 492 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,datafee)));
493 }
494 return("");
495}
496
497std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount)
498{
499 CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; uint8_t buf33[33]; char markeraddr[64];
500 cp = CCinit(&C,EVAL_ORACLES);
366625ca 501 if ( txfee == 0 )
502 txfee = 10000;
503 mypk = pubkey2pk(Mypubkey());
504 buf33[0] = 0x02;
5a53af78 505 endiancpy(&buf33[1],(uint8_t *)&oracletxid,32);
366625ca 506 markerpubkey = buf2pk(buf33);
fb6f9ce9 507 Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
366625ca 508 if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 )
509 {
510 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher));
ae846fcc 511 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG));
cb96789e 512 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('S',oracletxid,mypk,amount)));
366625ca 513 }
c926780f 514 return("");
515}
516
366625ca 517std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> data)
c926780f 518{
26ca942e 519 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];
c926780f 520 cp = CCinit(&C,EVAL_ORACLES);
cb96789e 521 mypk = pubkey2pk(Mypubkey());
366625ca 522 if ( data.size() > 8192 )
523 {
524 fprintf(stderr,"datasize %d is too big\n",(int32_t)data.size());
525 return("");
526 }
a2094466 527 if ( (datafee= OracleDatafee(pubKey,oracletxid,mypk)) <= 0 )
366625ca 528 {
529 fprintf(stderr,"datafee %.8f is illegal\n",(double)datafee/COIN);
530 return("");
531 }
c926780f 532 if ( txfee == 0 )
533 txfee = 10000;
366625ca 534 GetCCaddress(cp,coinaddr,mypk);
26ca942e 535 if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) // have enough funds even if baton utxo not there
c926780f 536 {
26ca942e 537 batonpk = OracleBatonPk(batonaddr,cp,mypk);
538 batontxid = OracleBatonUtxo(txfee,cp,oracletxid,batonaddr,mypk);
539 if ( batontxid != zeroid ) // not impossible to fail, but hopefully a very rare event
540 mtx.vin.push_back(CTxIn(batontxid,1,CScript()));
541 else fprintf(stderr,"warning: couldnt find baton utxo\n");
53314c07 542 if ( (inputs= AddOracleInputs(cp,mtx,mypk,datafee,60)) > 0 )
366625ca 543 {
544 if ( inputs > datafee )
545 CCchange = (inputs - datafee);
546 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
26ca942e 547 mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk));
548 mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
549 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data)));
366625ca 550 }
c926780f 551 }
552 return("");
553}
554
26ca942e 555int32_t oracle_format(char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen)
556{
a3532c80 557 int32_t sflag = 0,i,val32,len = 0,slen = 0; uint32_t uval32; uint16_t uval16; int16_t val16; int64_t val = 0; uint64_t uval = 0;
26ca942e 558 switch ( fmt )
559 {
560 case 's': slen = data[offset++]; break;
561 case 'S': slen = data[offset++]; slen |= ((int32_t)data[offset++] << 8); break;
562 case 'c': len = 1; sflag = 1; break;
563 case 'C': len = 1; break;
564 case 't': len = 2; sflag = 1; break;
565 case 'T': len = 2; break;
566 case 'i': len = 4; sflag = 1; break;
567 case 'I': len = 4; break;
568 case 'l': len = 8; sflag = 1; break;
569 case 'L': len = 8; break;
570 default: return(-1); break;
571 }
572 if ( slen != 0 )
573 {
574 for (i=0; i<slen; i++)
575 {
576 str[i] = data[offset++];
577 if ( offset >= datalen )
578 {
579 str[i] = 0;
580 return(-1);
581 }
582 }
583 str[i] = 0;
584 }
585 else if ( len != 0 && len+offset <= datalen )
586 {
587 if ( sflag != 0 )
588 {
589 switch ( len )
590 {
591 case 1: val = (int8_t)data[offset]; break;
592 case 2: iguana_rwnum(0,&data[offset],len,(void *)&val16); val = val16; break;
593 case 4: iguana_rwnum(0,&data[offset],len,(void *)&val32); val = val32; break;
594 case 8: iguana_rwnum(0,&data[offset],len,(void *)&val); break;
595 }
596 sprintf(str,"%lld",(long long)val);
597 }
598 else
599 {
600 switch ( len )
601 {
602 case 1: uval = data[offset]; break;
603 case 2: iguana_rwnum(0,&data[offset],len,(void *)&uval16); uval = uval16; break;
604 case 4: iguana_rwnum(0,&data[offset],len,(void *)&uval32); uval = uval32; break;
605 case 8: iguana_rwnum(0,&data[offset],len,(void *)&uval); break;
606 }
607 sprintf(str,"%llu",(long long)uval);
608 }
609 offset += len;
610 } else return(-1);
611 return(offset);
612}
613
614UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatlen)
615{
616 UniValue obj(UniValue::VARR); int32_t i,j=0; int64_t val; char str[16384];
617 for (i=0; i<formatlen && j<datalen; i++)
618 {
619 str[0] = 0;
620 j = oracle_format(str,format[i],data,j,datalen);
621 if ( j < 0 )
622 break;
623 obj.push_back(str);
624 if ( j >= datalen )
625 break;
626 }
627 return(obj);
628}
629
630UniValue OracleDataSamples(uint256 reforacletxid,uint256 batontxid,int32_t num)
631{
760ff4b8 632 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 633 result.push_back(Pair("result","success"));
634 if ( GetTransaction(reforacletxid,oracletx,hashBlock,false) != 0 && (numvouts=oracletx.vout.size()) > 0 )
635 {
636 if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' )
637 {
638 while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 )
639 {
640 if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,btxid,pk,data) == 'D' && reforacletxid == oracletxid )
641 {
642 if ( (formatstr= (char *)format.c_str()) == 0 )
3fd708a6 643 formatstr = (char *)"";
26ca942e 644 a.push_back(OracleFormat((uint8_t *)data.data(),(int32_t)data.size(),formatstr,(int32_t)format.size()));
645 batontxid = btxid;
646 if ( ++n >= num )
647 break;
648 } else break;
649 }
650 }
651 }
652 result.push_back(Pair("samples",a));
653 return(result);
654}
655
366625ca 656UniValue OracleInfo(uint256 origtxid)
c926780f 657{
26ca942e 658 UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ);
659 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
660 CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CMutableTransaction mtx; CPubKey Oraclespk,markerpubkey,pk; struct CCcontract_info *cp,C; uint8_t buf33[33]; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64];
c926780f 661 cp = CCinit(&C,EVAL_ORACLES);
662 Oraclespk = GetUnspendable(cp,0);
366625ca 663 buf33[0] = 0x02;
5a53af78 664 endiancpy(&buf33[1],(uint8_t *)&origtxid,32);
366625ca 665 markerpubkey = buf2pk(buf33);
fb6f9ce9 666 Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
667 if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
366625ca 668 {
fb6f9ce9 669 if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
366625ca 670 {
26ca942e 671 result.push_back(Pair("result","success"));
366625ca 672 result.push_back(Pair("txid",uint256_str(str,origtxid)));
673 result.push_back(Pair("name",name));
674 result.push_back(Pair("description",description));
26ca942e 675 result.push_back(Pair("format",format));
366625ca 676 result.push_back(Pair("marker",markeraddr));
26ca942e 677 SetCCunspents(unspentOutputs,markeraddr);
678 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
366625ca 679 {
680 txid = it->first.txhash;
681 if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
682 {
fb6f9ce9 683 if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
366625ca 684 {
26ca942e 685 obj.push_back(Pair("provider",pubkey33_str(str,(uint8_t *)pk.begin())));
686 Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
687 batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk);
688 obj.push_back(Pair("baton",batonaddr));
689 obj.push_back(Pair("batontxid",uint256_str(str,batontxid)));
366625ca 690 funding = LifetimeOraclesFunds(cp,oracletxid,pk);
691 sprintf(numstr,"%.8f",(double)funding/COIN);
692 obj.push_back(Pair("lifetime",numstr));
53314c07 693 funding = AddOracleInputs(cp,mtx,pk,0,0);
366625ca 694 sprintf(numstr,"%.8f",(double)funding/COIN);
695 obj.push_back(Pair("funds",numstr));
696 sprintf(numstr,"%.8f",(double)datafee/COIN);
697 obj.push_back(Pair("datafee",numstr));
698 a.push_back(obj);
699 }
700 }
701 }
702 result.push_back(Pair("registered",a));
703 }
704 }
705 return(result);
706}
707
708UniValue OraclesList()
709{
710 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];
711 cp = CCinit(&C,EVAL_ORACLES);
712 SetCCtxids(addressIndex,cp->normaladdr);
713 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
714 {
715 txid = it->first.txhash;
716 if ( GetTransaction(txid,createtx,hashBlock,false) != 0 )
717 {
cb96789e 718 if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
366625ca 719 {
720 result.push_back(uint256_str(str,txid));
721 }
722 }
723 }
c926780f 724 return(result);
725}
726
This page took 0.115986 seconds and 4 git commands to generate.