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