Merge remote-tracking branch 'origin/jl777' into jl777

This commit is contained in:
jl777
2018-09-05 20:35:16 -11:00
6 changed files with 126 additions and 16 deletions

View File

@@ -449,7 +449,99 @@ In order to mitigate this, the disclosure of the house entropy needs to be delay
Chapter 10 - lotto example
Chapter 11 - channels example
Chapter 11 - oracles example
Oracles CC is an example where it ended up being simpler than I first expected, but at the same time a lot more powerful. It is one of the smaller CC, but it enables creation of an arbitrary number of data markets, in a performant way.
In order to gain the performance, some clever usage of special addresses was needed. It was a bit tricky to generate a special address to keep track of the latest data.
Let's back up to the beginning. Just what is an oracle? In this context it is something that puts data that is not on the blockchain, onto the blockchain. Since everything other than the transactions and blocks are not in the blockchain, there is a very large universe of data that can be oracle-ized. It can be literally anything, from the obvious like prices to specific results relative to an arbitrary description.
The most difficult issue about oracles is that they need to be trusted to various degree to provide accurate and timely data. The danger is that if a trusted node is used to write data to the blockchain, it creates a trust point and a single point of attack. Ultimately there is nothing that can ensure only valid data is written to the blockchain, so what is done is to reinforce good behavior via pay per datapoint. However, for critical data, higher level processing is needed that combines multiple data providers into a validated signal.
At the oracles CC level, it is enough that there is financial incentive to provide good data. Also it is needed to allow multiple vendors for each data that is required and to enable efficient ways to update and query the data.
The following are the rpc calls:
oraclescreate name description format
oracleslist
oraclesinfo oracletxid
oraclesregister oracletxid datafee
oraclessubscribe oracletxid publisher amount
oraclesdata oracletxid hexstr
oraclessamples oracletxid batonutxo num
The first step is to create a specific data description with oraclescreate, which also defines the format of the binary data. This creates an oracletxid, which is used in the other rpc calls. name and description are just arbitrary strings, with name preferably being a short name used to access the data. The format is a string comprised of a single character per data element:
's' -> <256 char string
'S' -> <65536 char string
'd' -> <256 binary data
'D' -> <65536 binary data
'c' -> 1 byte signed little endian number, 'C' unsigned
't' -> 2 byte signed little endian number, 'T' unsigned
'i' -> 4 byte signed little endian number, 'I' unsigned
'l' -> 8 byte signed little endian number, 'L' unsigned
'h' -> 32 byte hash
For example, if the datapoint is comprised of a 4byte timestamp and an 8byte number the format string would be: "IL"
oracleslist displays a list of all the oraclestxid and oraclesinfo displays information about the specific oracletxid. Each oracletxid deterministically generates a marker address and a small amount is sent to that address to mark a transaction's relation to the oracltxid.
{
"result": "success",
"txid": "4895f631316a649e216153aee7a574bd281686265dc4e8d37597f72353facac3",
"name": "BTCUSD",
"description": "coindeskpricedata",
"format": "L",
"marker": "RVqJCSrdBm1gYJZS1h7dgtHioA5TEYzNRk",
"registered": [
{
"publisher": "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92",
"baton": "RKY4zmHJZ5mNtf6tfKE5VMsKoV71Euej3i",
"batontxid": "4de10b01242ce1a5e29d5fbb03098b4519976879e05ad0458ef7174ed9127f18",
"lifetime": "1.50000000",
"funds": "0.01000000",
"datafee": "0.01000000"
}
]
}
A data publisher needs to register a datafee and their pubkey for a specific oracletxid. datafee needs to be at least as big as a txfee. Using oraclesregister the current datafee can be updated so a publisher can adapt to market conditions. Once registered, subscribers can prepay for some number of datapoints to a specific publisher using the oraclessubscribe rpc. At first, it is likely that the publisher would pay themselves to enable the posting of initial data points so the potential subscribers can evaluate the quality and consistency of the data.
The one final rpc is oraclessamples, which returns the most recent samples of data from a specific publisher. In order to have a performant solution to track all the potential data streams from all the publishers for all the oracletxid, a baton utxo is used. This is an output sent to a specific address and expected to have just a single utxo at any given time to allow for direct lookup. oraclessamples requires a starting txid to use and with each datapoint having the prior batontxid, there is a reverse linked list to traverse the most recent data.
In order to implement this, the following vin/vout contraints are used:
create:
vins.*: normal inputs
vout.0: txfee tag to oracle normal address
vout.1: change, if any
vout.n-1: opreturn with name and description and format for data
register:
vins.*: normal inputs
vout.0: txfee tag to normal marker address
vout.1: baton CC utxo
vout.2: change, if any
vout.n-1: opreturn with oracletxid, pubkey and price per data point
subscribe:
vins.*: normal inputs
vout.0: subscription fee to publishers CC address
vout.1: change, if any
vout.n-1: opreturn with oracletxid, registered provider's pubkey, amount
data:
vin.0: normal input
vin.1: baton CC utxo (most of the time)
vin.2+: subscription or data vout.0
vout.0: change to publishers CC address
vout.1: baton CC utxo
vout.2: payment for dataprovider
vout.3: change, if any
vout.n-1: opreturn with oracletxid, prevbatontxid and data in proper format
The oraclesdata transaction is the most complex as it needs to find and spend the baton utxo, use the correct datafee and spend funds from the locked subscription funds. With the above, the oracles CC is complete and allows the creations of massively parallel data streams from multiple vendors that uses free market feedback via payments, ie. poorly performing providers wont get renewals.
I expect that at first, the data providers will just be dapp developers deploying a working system including the required data, but its structure allows open market competition. Of course, specific dapps could restrict themselves to using only publishers from a whitelist of pubkeys. The potential usecases for oracles CC is quite varied and limited only by the imagination.
Chapter 12 - limitless possibilities
As can be seen, CC contracts can do a wide range of things and since they are Turing complete, we know that this is true. However, what is more important is the added security gained from using a utxo based system. While in some ways it is more complex to have to deal with utxo, as can be seen by the above examples, it is either solved and made invisible at the rpc level, or actually used as part of the solution.

View File

@@ -47,6 +47,7 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include "../wallet/wallet.h"
#include <univalue.h>
#include <exception>
#include "../komodo_defs.h"
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE;
extern uint32_t ASSETCHAINS_CC;

View File

@@ -382,6 +382,12 @@ void komodobroadcast(char *acname,cJSON *hexjson)
]
]
}
oraclescreate test testsformat s -> 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff
oraclesregister -> 7825ad75ba854ab12868f7d2e06b4061903687fe93f41a2a99202a6b9ca3c029
oraclessubscribe 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 1.5 -> faf8a6676f6389abad9e7f397015d200395c9f8a24c4ded291d83e6265b2f4d1
oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 03404040 -> e8a8c897e97389dcac31d81b617ab73a829110bd5c6f99f9f533b9c0e22700d0
*/
#define ORACLETXID "4895f631316a649e216153aee7a574bd281686265dc4e8d37597f72353facac3"

View File

@@ -46,12 +46,13 @@
The format string is a set of chars with the following meaning:
's' -> <256 char string
'S' -> <65536 char string
'd' -> <256 binary data
'D' -> <65536 binary data
'c' -> 1 byte signed little endian number, 'C' unsigned
't' -> 2 byte signed little endian number, 'T' unsigned
'i' -> 4 byte signed little endian number, 'I' unsigned
'l' -> 8 byte signed little endian number, 'L' unsigned
'h' -> 32 byte hash
uppercase is unsigned, lowercase is a signed number
create:
vins.*: normal inputs
@@ -280,13 +281,17 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora
int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen)
{
char _str[65]; 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;
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;
*valp = 0;
*hashp = zeroid;
if ( str != 0 )
str[0] = 0;
switch ( fmt )
{
case 's': slen = data[offset++]; break;
case 'S': slen = data[offset++]; slen |= ((int32_t)data[offset++] << 8); break;
case 'd': dlen = data[offset++]; break;
case 'D': dlen = data[offset++]; dlen |= ((int32_t)data[offset++] << 8); break;
case 'c': len = 1; sflag = 1; break;
case 'C': len = 1; break;
case 't': len = 2; sflag = 1; break;
@@ -302,16 +307,24 @@ int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t
{
if ( str != 0 )
{
for (i=0; i<slen; i++)
if ( slen < IGUANA_MAXSCRIPTSIZE && offset+slen <= datalen )
{
str[i] = data[offset++];
if ( offset >= datalen )
{
str[i] = 0;
return(-1);
}
}
str[i] = 0;
for (i=0; i<slen; i++)
str[i] = data[offset++];
str[i] = 0;
} else return(-1);
}
}
else if ( dlen != 0 )
{
if ( str != 0 )
{
if ( dlen < IGUANA_MAXSCRIPTSIZE && offset+dlen <= datalen )
{
for (i=0; i<dlen; i++)
sprintf(&str[i<<1],"%02x",data[offset++]);
str[i] = 0;
} else return(-1);
}
}
else if ( len != 0 && len+offset <= datalen )
@@ -502,8 +515,6 @@ bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransactio
}
}
}
else if ( i < 2 )
return eval->Invalid("vout0 or vout1 is normal");
}
if ( inputs != outputs+datafee )
{
@@ -735,7 +746,7 @@ std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector <uint8_t> da
UniValue OracleFormat(uint8_t *data,int32_t datalen,char *format,int32_t formatlen)
{
UniValue obj(UniValue::VARR); uint256 hash; int32_t i,j=0; int64_t val; char str[16384];
UniValue obj(UniValue::VARR); uint256 hash; int32_t i,j=0; int64_t val; char str[IGUANA_MAXSCRIPTSIZE*2+1];
for (i=0; i<formatlen && j<datalen; i++)
{
str[0] = 0;

View File

@@ -6,6 +6,7 @@
#define ROUNDROBIN_DELAY 61
#define KOMODO_ASSETCHAIN_MAXLEN 65
#define KOMODO_LIMITED_NETWORKSIZE 4
#define IGUANA_MAXSCRIPTSIZE 10001
#define KOMODO_MAXMEMPOOLTIME 3600 // affects consensus
#define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9"

View File

@@ -33,7 +33,6 @@ int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max);
pthread_mutex_t komodo_mutex;
#define KOMODO_ELECTION_GAP 2000 //((ASSETCHAINS_SYMBOL[0] == 0) ? 2000 : 100)
#define IGUANA_MAXSCRIPTSIZE 10001
#define KOMODO_ASSETCHAIN_MAXLEN 65
struct pax_transaction *PAX;