Initial oracles CC without validation

This commit is contained in:
jl777
2018-09-02 03:40:52 -11:00
parent bea5d28567
commit 366625ca23
14 changed files with 371 additions and 48 deletions

View File

@@ -16,6 +16,46 @@
#include "CCOracles.h"
/*
An oracles CC has the purpose of converting offchain data into onchain data
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
That begs the question, "what would an oracles CC do?"
A couple of things come to mind, ie. payments to oracles for future offchain data and maybe some sort of dispute/censoring ability
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.
linked to this txid would be two types of transactions:
a) oracle providers
b) oracle data users
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.
Required transactions:
0) create oracle description -> just needs to create txid for oracle data
1) register as oracle data provider with price -> become a registered oracle data provider
2) pay provider for N oracle data points -> lock funds for oracle provider
3) publish oracle data point -> publish data and collect payment
create:
vins.*: normal inputs
vout.0: txfee tag to oracle normal address
vout.1: opreturn with name and description and format for data
register:
vins.*: normal inputs
vout.0: txfee tag to normal marker address
vout.1: opreturn with createtxid, pubkey and price per data point
subscribe:
vins.*: normal inputs
vout.0: subscription fee to publishers CC address
vout.1: opreturn with createtxid, registered provider's pubkey, amount
data:
vin.0: normal input
vin.1+: subscription vout.0
vout.0: change to publishers CC address
vout.1: payment for dataprovider
vout.2: opreturn with data in proper format
*/
@@ -139,73 +179,188 @@ int64_t AddOraclesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPu
return(totalinputs);
}
std::string OraclesGet(uint64_t txfee,int64_t nValue)
int64_t LifetimeOraclesFunds(struct CCcontract_info *cp,uint256 oracletxid,CPubKey regpk)
{
CMutableTransaction mtx,tmpmtx; CPubKey mypk,Oraclespk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
cp = CCinit(&C,EVAL_ORACLES);
if ( txfee == 0 )
txfee = 10000;
Oraclespk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddOraclesInputs(cp,mtx,Oraclespk,nValue+txfee,60)) > 0 )
char coinaddr[64]; CPubKey pk; int64_t total=0,num; uint256 txid,hashBlock; CTransaction subtx;
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
GetCCaddress(cp,coinaddr,regpk);
SetCCtxids(addressIndex,coinaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ORACLES,CCchange,Oraclespk));
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
fprintf(stderr,"start at %u\n",(uint32_t)time(NULL));
j = rand() & 0xfffffff;
for (i=0; i<1000000; i++,j++)
txid = it->first.txhash;
if ( GetTransaction(txid,subtx,hashBlock,false) != 0 )
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_ORACLES << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
if ( subtx.vout.size() > 0 && DecodeOraclesOpRet(subtx.vout[subtx.vout.size()-1].scriptPubKey,subtxid,pk,num) == 'S' && subtxid == oracletxid && regpk == pk )
{
len >>= 1;
decode_hex(buf,len,(char *)rawhex.c_str());
hash = bits256_doublesha256(0,buf,len);
if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 )
{
fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL));
return(rawhex);
}
//fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]);
total += subtx.vout[0].nValue;
}
}
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
return("");
} else fprintf(stderr,"cant find Oracles inputs\n");
return("");
}
return(total);
}
std::string OraclesFund(uint64_t txfee,int64_t funds)
std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format)
{
CMutableTransaction mtx; CPubKey mypk,Oraclespk; CScript opret; struct CCcontract_info *cp,C;
CMutableTransaction mtx; CPubKey mypk,Oraclespk; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_ORACLES);
if ( name.size() > 32 || description.size() > 4096 || format.size() > 4096 )
{
fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
return("");
}
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
Oraclespk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
{
mtx.vout.push_back(MakeCC1vout(EVAL_ORACLES,funds,Oraclespk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(Oraclespk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesCreateOpRet('C',name,description,format)));
}
return("");
}
UniValue OraclesInfo()
std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee)
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx; CPubKey Oraclespk; struct CCcontract_info *cp,C; int64_t funding;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Oracles"));
CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; uint8_t buf33[33]; char markeraddr[64];
cp = CCinit(&C,EVAL_ORACLES);
if ( name.size() > 32 || description.size() > 4096 || format.size() > 4096 )
{
fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
return("");
}
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
buf33[0] = 0x02;
endiancpy(&buf[1],(uint8_t *)&oracletxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << markerpubkey << OP_CHECKSIG);
if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
{
mtx.vout.push_back(CTxOut(txfee,CScript() << markerpubkey << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,datafee)));
}
return("");
}
std::string OracleSubscribe(int64_t txfee,uint256 oracletxid,CPubKey publisher,int64_t amount)
{
CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; uint8_t buf33[33]; char markeraddr[64];
cp = CCinit(&C,EVAL_ORACLES);
if ( name.size() > 32 || description.size() > 4096 || format.size() > 4096 )
{
fprintf(stderr,"name.%d or description.%d is too big\n",(int32_t)name.size(),(int32_t)description.size());
return("");
}
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
buf33[0] = 0x02;
endiancpy(&buf[1],(uint8_t *)&oracletxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << markerpubkey << OP_CHECKSIG);
if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher));
mtx.vout.push_back(CTxOut(txfee,CScript() << markerpubkey << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesOpRet('R',oracletxid,mypk,amount)));
}
return("");
}
std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> data)
{
CMutableTransaction mtx; CPubKey mypk; int64_t datafee,inputs,CCchange = 0; struct CCcontract_info *cp,C; char coinaddr[64];
cp = CCinit(&C,EVAL_ORACLES);
if ( data.size() > 8192 )
{
fprintf(stderr,"datasize %d is too big\n",(int32_t)data.size());
return("");
}
if ( (datafee= OracleDatafee(oracletxid)) <= 0 )
{
fprintf(stderr,"datafee %.8f is illegal\n",(double)datafee/COIN);
return("");
}
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
GetCCaddress(cp,coinaddr,mypk);
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( (inputs= AddOracleInputs(cp,mtx,mypk,oracletxid,datafee,60)) > 0 )
{
if ( inputs > datafee )
CCchange = (inputs - datafee);
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
mtx.vout.push_back(CTxOut(txfee,CScript() << mypk << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,mypk,data)));
}
}
return("");
}
UniValue OracleInfo(uint256 origtxid)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; CTransaction regtx; std::string name,description,format; uint256 hashBlock,txid,oracletxid; CMutableTransaction mtx; CPubKey Oraclespk,markerpubkey; struct CCcontract_info *cp,C; uint8_t buf33[33]; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64];
cp = CCinit(&C,EVAL_ORACLES);
Oraclespk = GetUnspendable(cp,0);
funding = AddOraclesInputs(cp,mtx,Oraclespk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
buf33[0] = 0x02;
endiancpy(&buf[1],(uint8_t *)&origtxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << markerpubkey << OP_CHECKSIG);
if ( GetTransaction(origtxid,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && DecodeOraclesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
{
result.push_back(Pair("txid",uint256_str(str,origtxid)));
result.push_back(Pair("name",name));
result.push_back(Pair("description",description));
result.push_back(Pair("marker",markeraddr));
SetCCtxids(addressIndex,markeraddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
{
result.push_back(Pair("provider",pubkey33_str(str,(uint8_t *)pk.begin())));
funding = LifetimeOraclesFunds(cp,oracletxid,pk);
sprintf(numstr,"%.8f",(double)funding/COIN);
obj.push_back(Pair("lifetime",numstr));
funding = AddOraclesInputs(cp,mtx,pk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
obj.push_back(Pair("funds",numstr));
sprintf(numstr,"%.8f",(double)datafee/COIN);
obj.push_back(Pair("datafee",numstr));
a.push_back(obj);
}
}
}
result.push_back(Pair("registered",a));
}
}
return(result);
}
UniValue OraclesList()
{
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];
cp = CCinit(&C,EVAL_ORACLES);
SetCCtxids(addressIndex,cp->normaladdr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,createtx,hashBlock,false) != 0 )
{
if ( createtx.vout.size() > 0 && DecodeOraclesFundingOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' )
{
result.push_back(uint256_str(str,txid));
}
}
}
return(result);
}