Merge branch 'jl777' into FSM

This commit is contained in:
jl777
2018-09-09 22:15:17 -11:00
31 changed files with 1112 additions and 265 deletions

View File

@@ -36,6 +36,7 @@ BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \
$(top_srcdir)/contrib/devtools/security-check.py $(top_srcdir)/contrib/devtools/security-check.py
WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \ WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \
$(top_srcdir)/share/pixmaps/nsis-header.bmp \ $(top_srcdir)/share/pixmaps/nsis-header.bmp \
$(top_srcdir)/share/pixmaps/nsis-wizard.bmp $(top_srcdir)/share/pixmaps/nsis-wizard.bmp

View File

@@ -0,0 +1,12 @@
rpcuser=dontuseweakusernameoryougetrobbed
rpcpassword=dontuseweakpasswordoryougetrobbed
txindex=1
server=1
rpcworkqueue=64
addnode=5.9.102.210
addnode=78.47.196.146
addnode=178.63.69.164
addnode=88.198.65.74
addnode=5.9.122.241
addnode=144.76.94.38
addnode=89.248.166.91

View File

@@ -1,61 +0,0 @@
# MigrateCoin protocol
## ExportCoins tx:
```
vin:
[ any ]
vout:
- amount: {burnAmount}
script: OP_RETURN "send to ledger {id} {voutsHash}"
```
* ExportCoin is a standard tx which burns coins in an OP_RETURN
## ImportCoins tx:
```
vin:
- txid: 0000000000000000000000000000000000000000000000000000000000000000
idx: 0
script: CC_EVAL(EVAL_IMPORTCOINS, {momoProof},{exportCoin}) OP_CHECKCRYPTOCONDITION_UNILATERAL
vout:
- [ vouts matching voutsHash in exportCoin ]
```
* ImportCoin transaction has no signature
* ImportCoin is non malleable
* ImportCoin satisfies tx.IsCoinBase()
* ImportCoin uses a new opcode which allows a one sided check (no scriptPubKey)
* ImportCoin must contain CC opcode EVAL_IMPORTCOINS
* ImportCoin fees are equal to the difference between burnAmount in exportCoins and the sum of outputs.

43
migratecoin.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/bash
# This script makes the neccesary transactions to migrate
# coin between 2 assetchains on the same -ac_cc id
set -e
source=TXSCL
target=TXSCL000
address="RFw7byY4xZpZCrtkMk3nFuuG1NTs9rSGgQ"
amount=1
# Alias for running cli on source chain
cli_source="komodo-cli -ac_name=$source"
# Raw tx that we will work with
txraw=`$cli_source createrawtransaction "[]" "{\"$address\":$amount}"`
# Convert to an export tx
exportData=`$cli_source migrate_converttoexport $txraw $target $amount`
exportRaw=`echo $exportData | jq -r .exportTx`
exportPayouts=`echo $exportData | jq -r .payouts`
# Fund
exportFundedData=`$cli_source fundrawtransaction $exportRaw`
exportFundedTx=`echo $exportFundedData | jq -r .hex`
# Sign
exportSignedData=`$cli_source signrawtransaction $exportFundedTx`
exportSignedTx=`echo $exportSignedData | jq -r .hex`
# Send
echo "Sending export tx"
$cli_source sendrawtransaction $exportSignedTx
read -p "Wait for a notarisation to KMD, and then two more notarisations from the target chain, and then press enter to continue"
# Create import
importTx=`$cli_source migrate_createimporttransaction $exportSignedTx $payouts`
importTx=`komodo-cli migrate_completeimporttransaction $importTx`
# Send import
komodo-cli -ac_name=$target sendrawtransaction $importTx

View File

@@ -422,7 +422,6 @@ class CryptoConditionsTest (BitcoinTestFramework):
result = rpc.tokenbid("100", "deadbeef", "1") result = rpc.tokenbid("100", "deadbeef", "1")
assert_error(result) assert_error(result)
# valid bid
tokenbid = rpc.tokenbid("100", tokenid, "10") tokenbid = rpc.tokenbid("100", tokenid, "10")
tokenbidhex = tokenbid['hex'] tokenbidhex = tokenbid['hex']
tokenbidid = self.send_and_mine(tokenbid['hex']) tokenbidid = self.send_and_mine(tokenbid['hex'])
@@ -595,6 +594,7 @@ class CryptoConditionsTest (BitcoinTestFramework):
print("Importing privkey") print("Importing privkey")
rpc.importprivkey(self.privkey) rpc.importprivkey(self.privkey)
# self.run_faucet_tests()
self.run_rewards_tests() self.run_rewards_tests()
self.run_dice_tests() self.run_dice_tests()
self.run_token_tests() self.run_token_tests()

View File

@@ -45,7 +45,8 @@
}, },
{ {
"ac_name": "COQUI", "ac_name": "COQUI",
"ac_supply": "72000000" "ac_supply": "72000000",
"ac_ccactivate": "200000"
}, },
{ {
"ac_name": "WLC", "ac_name": "WLC",
@@ -140,7 +141,9 @@
"ac_cc": "2", "ac_cc": "2",
"addressindex": "1", "addressindex": "1",
"spentindex": "1", "spentindex": "1",
"addnode": "142.93.136.89", "addnode": [
"addnode": "195.201.22.89" "142.93.136.89",
"195.201.22.89"
]
} }
] ]

View File

@@ -15,7 +15,7 @@ echo $pubkey
./komodod -pubkey=$pubkey -ac_name=MSHARK -ac_supply=1400000 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=MSHARK -ac_supply=1400000 -addnode=78.47.196.146 $1 &
./komodod -pubkey=$pubkey -ac_name=BOTS -ac_supply=999999 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=BOTS -ac_supply=999999 -addnode=78.47.196.146 $1 &
./komodod -pubkey=$pubkey -ac_name=MGW -ac_supply=999999 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=MGW -ac_supply=999999 -addnode=78.47.196.146 $1 &
./komodod -pubkey=$pubkey -ac_name=COQUI -ac_supply=72000000 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=COQUI -ac_supply=72000000 -ac_ccactivate=200000 -addnode=78.47.196.146 $1 &
./komodod -pubkey=$pubkey -ac_name=WLC -ac_supply=210000000 -addnode=148.251.190.89 $1 & ./komodod -pubkey=$pubkey -ac_name=WLC -ac_supply=210000000 -addnode=148.251.190.89 $1 &
./komodod -pubkey=$pubkey -ac_name=KV -ac_supply=1000000 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=KV -ac_supply=1000000 -addnode=78.47.196.146 $1 &
./komodod -pubkey=$pubkey -ac_name=CEAL -ac_supply=366666666 -addnode=78.47.196.146 $1 & ./komodod -pubkey=$pubkey -ac_name=CEAL -ac_supply=366666666 -addnode=78.47.196.146 $1 &

View File

@@ -20,8 +20,13 @@
#include "CCinclude.h" #include "CCinclude.h"
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys);
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,std::vector<CPubKey>pubkeys,int32_t height,std::string refcoin,uint256 cointxid,std::string deposithex,std::vector<uint256>proof,std::vector<uint8_t> claimpubkey,int64_t amount);
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string coin,uint256 deposittxid,std::string claimaddr,int64_t amount);
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount);
// CCcustom // CCcustom
UniValue GatewaysInfo(); UniValue GatewaysInfo(uint256 bindtxid);
UniValue GatewaysList();
#endif #endif

View File

@@ -19,8 +19,6 @@
#include "CCinclude.h" #include "CCinclude.h"
#define ORACLES_MAXPROVIDERS 64
bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format); std::string OracleCreate(int64_t txfee,std::string name,std::string description,std::string format);
std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee); std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee);

View File

@@ -223,16 +223,16 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
for (i=0; i<n; i++) for (i=0; i<n; i++)
total += amounts[i];*/ total += amounts[i];*/
mask = ~((1LL << mtx.vin.size()) - 1); mask = ~((1LL << mtx.vin.size()) - 1);
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 ) if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 )
{ {
if ( inputs > total ) if ( inputs > total )
CCchange = (inputs - total); CCchange = (inputs - total);
//for (i=0; i<n; i++) //for (i=0; i<n; i++)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,total,pubkey2pk(destpubkey))); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,total,pubkey2pk(destpubkey)));
if ( CCchange != 0 ) if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey()))); return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN); } else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size()); //} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
} }
return(""); return("");

View File

@@ -76,6 +76,13 @@ struct CCcontract_info
}; };
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode); struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode);
struct oracleprice_info
{
CPubKey pk;
std::vector <uint8_t> data;
int32_t height;
};
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
extern CWallet* pwalletMain; extern CWallet* pwalletMain;
#endif #endif
@@ -92,8 +99,20 @@ bool mySendrawtransaction(std::string res);
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp); int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp);
int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp); int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp);
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
int64_t CCaddress_balance(char *coinaddr);
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format); int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
uint256 OracleMerkle(int32_t height,uint256 reforacletxid,char *format,std::vector<struct oracle_merklepair>publishers);
uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk);
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey);
uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data);
int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen);
CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey);
// CCcustom // CCcustom
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv); CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
@@ -114,6 +133,9 @@ char *uint256_str(char *dest,uint256 txid);
char *pubkey33_str(char *dest,uint8_t *pubkey33); char *pubkey33_str(char *dest,uint8_t *pubkey33);
uint256 Parseuint256(char *hexstr); uint256 Parseuint256(char *hexstr);
CPubKey pubkey2pk(std::vector<uint8_t> pubkey); CPubKey pubkey2pk(std::vector<uint8_t> pubkey);
int64_t CCfullsupply(uint256 tokenid);
int64_t CCtoken_balance(char *destaddr,uint256 tokenid);
bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk);
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk); bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk);
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2); bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2);
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue); bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue);

View File

@@ -212,6 +212,48 @@ int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
return(0); return(0);
} }
int64_t CCaddress_balance(char *coinaddr)
{
int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
sum += it->second.satoshis;
}
return(sum);
}
int64_t CCfullsupply(uint256 tokenid)
{
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeAssetCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description) > 0 )
{
return(tx.vout[0].nValue);
}
}
return(0);
}
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
{
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector<uint8_t> origpubkey; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 && assetid == tokenid )
{
sum += it->second.satoshis;
}
}
}
return(sum);
}
int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *belowp,struct CC_utxo utxos[],int32_t numunspents,int64_t value) int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *belowp,struct CC_utxo utxos[],int32_t numunspents,int64_t value)
{ {
int32_t i,abovei,belowi; int64_t above,below,gap,atx_value; int32_t i,abovei,belowi; int64_t above,below,gap,atx_value;

View File

@@ -181,13 +181,11 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
return(false); return(false);
} }
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk) bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
{ {
CC *payoutCond; CC *payoutCond;
destaddr[0] = 0; destaddr[0] = 0;
if ( pk.size() == 0 ) if ( (payoutCond= MakeCCcond1(evalcode,pk)) != 0 )
pk = GetUnspendable(cp,0);
if ( (payoutCond= MakeCCcond1(cp->evalcode,pk)) != 0 )
{ {
Getscriptaddress(destaddr,CCPubKey(payoutCond)); Getscriptaddress(destaddr,CCPubKey(payoutCond));
cc_free(payoutCond); cc_free(payoutCond);
@@ -195,6 +193,14 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
return(destaddr[0] != 0); return(destaddr[0] != 0);
} }
bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
{
destaddr[0] = 0;
if ( pk.size() == 0 )
pk = GetUnspendable(cp,0);
return(_GetCCaddress(destaddr,cp->evalcode,pk));
}
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2) bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
{ {
CC *payoutCond; CC *payoutCond;

View File

@@ -325,31 +325,6 @@ cJSON *get_komodocli(char **retstrp,char *acname,char *method,char *arg0,char *a
return(retjson); return(retjson);
} }
void bntn()
{
long fsize; int32_t i,n; cJSON *item,*retjson = 0; char cmdstr[32768],*jsonstr,*addr; double val;
if ( (jsonstr= filestr(&fsize,"bntn")) != 0 )
{
if ( (retjson= cJSON_Parse(jsonstr)) != 0 )
{
if ( (n= cJSON_GetArraySize(retjson)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(retjson,i);
if ( (addr= jstr(item,"KMD Address")) != 0 && (val= jdouble(item,"(BNTN)")) > 0 )
{
val = 1387;
if ( addr[0] == 'z' )
printf("./komodo-cli -ac_name=BNTN sendtoaddress %s %.8f\n",addr,val);
}
}
}
free_json(retjson);
}
}
}
void komodobroadcast(char *acname,cJSON *hexjson) void komodobroadcast(char *acname,cJSON *hexjson)
{ {
char *hexstr,*retstr; cJSON *retjson; char *hexstr,*retstr; cJSON *retjson;

84
src/cc/disputepayout.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include <cryptoconditions.h>
#include "hash.h"
#include "chain.h"
#include "version.h"
#include "script/cc.h"
#include "cc/eval.h"
#include "cc/betprotocol.h"
#include "primitives/transaction.h"
/*
* Crypto-Condition EVAL method that resolves a dispute of a session
*
* IN: vm - AppVM virtual machine to verify states
* IN: params - condition params
* IN: disputeTx - transaction attempting to resolve dispute
* IN: nIn - index of input of dispute tx
*
* disputeTx: attempt to resolve a dispute
*
* in 0: Spends Session TX first output, reveals DisputeHeader
* out 0: OP_RETURN hash of payouts
*/
bool Eval::DisputePayout(AppVM &vm, std::vector<uint8_t> params, const CTransaction &disputeTx, unsigned int nIn)
{
if (disputeTx.vout.size() == 0) return Invalid("no-vouts");
// get payouts hash
uint256 payoutHash;
if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash))
return Invalid("invalid-payout-hash");
// load params
uint16_t waitBlocks;
std::vector<uint8_t> vmParams;
if (!E_UNMARSHAL(params, ss >> VARINT(waitBlocks); ss >> vmParams))
return Invalid("malformed-params");
// ensure that enough time has passed
{
CTransaction sessionTx;
CBlockIndex sessionBlock;
// if unconformed its too soon
if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock))
return Error("couldnt-get-parent");
if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks)
return Invalid("dispute-too-soon"); // Not yet
}
// get spends
std::vector<CTransaction> spends;
if (!GetSpendsConfirmed(disputeTx.vin[0].prevout.hash, spends))
return Error("couldnt-get-spends");
// verify result from VM
int maxLength = -1;
uint256 bestPayout;
for (int i=1; i<spends.size(); i++)
{
std::vector<unsigned char> vmState;
if (spends[i].vout.size() == 0) continue;
if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue;
auto out = vm.evaluate(vmParams, vmState);
uint256 resultHash = SerializeHash(out.second);
if (out.first > maxLength) {
maxLength = out.first;
bestPayout = resultHash;
}
// The below means that if for any reason there is a draw, the first dispute wins
else if (out.first == maxLength) {
if (bestPayout != payoutHash) {
fprintf(stderr, "WARNING: VM has multiple solutions of same length\n");
bestPayout = resultHash;
}
}
}
if (maxLength == -1) return Invalid("no-evidence");
return bestPayout == payoutHash ? Valid() : Invalid("wrong-payout");
}

View File

@@ -20,11 +20,80 @@
the potential pubkeys to be used would be based on active oracle data providers with recent activity. the potential pubkeys to be used would be based on active oracle data providers with recent activity.
bind asset <-> KMD gateway deposit address
KMD deposit -> globally spendable marker utxo
spend marker utxo and spend linked/locked asset to user's CC address
redeem -> asset to global CC address with withdraw address -> gateway spendable marker utxo
spend market utxo and withdraw from gateway deposit address
rpc calls:
GatewayList
GatewayInfo bindtxid
GatewayBind coin tokenid M N pubkey(s)
external: deposit to depositaddr with claimpubkey
GatewayDeposit coin tokenid external.deposittxid -> markertxid
GatewayClaim coin tokenid external.deposittxid markertxid -> spend marker and deposit asset
GatewayWithdraw coin tokenid withdrawaddr
external: do withdraw to withdrawaddr and spend marker, support for partial signatures and autocomplete
deposit addr can be 1 to MofN pubkeys
1:1 gateway with native coin
*/ */
// start of consensus code // start of consensus code
CScript EncodeGatewaysBindOpRet(uint8_t funcid,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2)
{
CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys);
return(opret);
}
CScript EncodeGatewaysOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256>txids,int32_t height,uint256 cointxid,std::string deposithex,std::vector<uint256>proof,std::vector<uint8_t> redeemscript,int64_t amount)
{
CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << deposithex << proof << redeemscript << amount);
return(opret);
}
uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector<CPubKey>&publishers,std::vector<uint256>&txids,int32_t &height,uint256 &cointxid,std::string &deposithex,std::vector<uint256> &proof,std::vector<uint8_t> &redeemscript,int64_t &amount)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> deposithex; ss >> proof; ss >> redeemscript; ss >> amount) != 0 )
{
return(f);
}
return(0);
}
uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector<CPubKey> &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
depositaddr[0] = 0;
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> prefix; ss >> prefix2; ss >> taddr; ss >> tokenid; ss >> totalsupply; ss >> M; ss >> N; ss >> pubkeys) != 0 )
{
if ( prefix == 60 )
{
if ( N > 1 )
Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys));
else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG);
}
else
{
fprintf(stderr,"need to generate non-KMD addresses\n");
}
return(f);
}
return(0);
}
int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
{ {
char destaddr[64]; char destaddr[64];
@@ -128,7 +197,7 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
// no need to prevent dup // no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{ {
if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 ) if ( (nValue= IsGatewaysvout(cp,vintx,vout)) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
{ {
if ( total != 0 && maxinputs != 0 ) if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript())); mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -143,73 +212,353 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
return(totalinputs); return(totalinputs);
} }
std::string GatewaysGet(uint64_t txfee,int64_t nValue) UniValue GatewaysInfo(uint256 bindtxid)
{ {
CMutableTransaction mtx,tmpmtx; CPubKey mypk,Gatewayspk; 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; UniValue result(UniValue::VOBJ); std::string coin; char str[65],numstr[65],depositaddr[64]; uint8_t M,N; std::vector<CPubKey> pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int64_t totalsupply,remaining;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
Gatewayspk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddGatewaysInputs(cp,mtx,Gatewayspk,nValue+txfee,60)) > 0 )
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,Gatewayspk));
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++)
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_GATEWAYS << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
{
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]);
}
}
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
return("");
} else fprintf(stderr,"cant find Gateways inputs\n");
return("");
}
std::string GatewaysFund(uint64_t txfee,int64_t funds)
{
CMutableTransaction mtx; CPubKey mypk,Gatewayspk; CScript opret; struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
Gatewayspk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
{
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,funds,Gatewayspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
return("");
}
UniValue GatewaysInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int64_t funding;
result.push_back(Pair("result","success")); result.push_back(Pair("result","success"));
result.push_back(Pair("name","Gateways")); result.push_back(Pair("name","Gateways"));
cp = CCinit(&C,EVAL_GATEWAYS); cp = CCinit(&C,EVAL_GATEWAYS);
Gatewayspk = GetUnspendable(cp,0); Gatewayspk = GetUnspendable(cp,0);
funding = AddGatewaysInputs(cp,mtx,Gatewayspk,0,0); if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 )
sprintf(numstr,"%.8f",(double)funding/COIN); {
result.push_back(Pair("funding",numstr)); if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 )
{
depositaddr[0] = 0;
if ( N > 1 )
{
result.push_back(Pair("M",M));
result.push_back(Pair("N",N));
}
result.push_back(Pair("coin",coin));
result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
result.push_back(Pair("taddr",taddr));
result.push_back(Pair("prefix",prefix));
result.push_back(Pair("prefix2",prefix2));
result.push_back(Pair("deposit",depositaddr));
result.push_back(Pair("tokenid",uint256_str(str,tokenid)));
sprintf(numstr,"%.8f",(double)totalsupply/COIN);
result.push_back(Pair("totalsupply",numstr));
remaining = CCaddress_balance(depositaddr);
sprintf(numstr,"%.8f",(double)remaining/COIN);
result.push_back(Pair("remaining",numstr));
sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN);
result.push_back(Pair("issued",numstr));
}
}
return(result); return(result);
} }
UniValue GatewaysList()
{
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid,tokenid; CTransaction vintx; std::string coin; int64_t totalsupply; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector<CPubKey> pubkeys;
cp = CCinit(&C,EVAL_GATEWAYS);
SetCCtxids(addressIndex,cp->unspendableCCaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 )
{
result.push_back(uint256_str(str,txid));
}
}
}
return(result);
}
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys)
{
CMutableTransaction mtx; CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char destaddr[64],coinaddr[64],str[65],*fstr;
cp = CCinit(&C,EVAL_GATEWAYS);
if ( N == 0 || N > 15 || M > N )
{
fprintf(stderr,"illegal M.%d or N.%d\n",M,N);
return("");
}
if ( strcmp((char *)"KMD",coin.c_str()) != 0 )
{
fprintf(stderr,"only KMD supported for now\n");
return("");
}
taddr = 0;
prefix = 60;
prefix2 = 85;
if ( pubkeys.size() != N )
{
fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size());
return("");
}
for (i=0; i<N; i++)
{
Getscriptaddress(coinaddr,CScript() << ParseHex(HexStr(pubkeys[i])) << OP_CHECKSIG);
if ( CCaddress_balance(coinaddr) == 0 )
{
fprintf(stderr,"M.%d N.%d but pubkeys[%d] has no balance\n",M,N,i);
return("");
}
}
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( _GetCCaddress(destaddr,EVAL_ASSETS,gatewayspk) == 0 )
{
fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid));
return("");
}
if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply )
{
fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s totalsupply %.8f != fullsupply %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)totalsupply/COIN,(double)fullsupply/COIN);
return("");
}
if ( CCtoken_balance(destaddr,tokenid) != totalsupply )
{
fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)totalsupply/COIN);
return("");
}
if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find oracletxid %s\n",uint256_str(str,oracletxid));
return("");
}
if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' )
{
fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str());
return("");
}
if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 )
{
fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh");
return("");
}
fprintf(stderr,"implement GatewaysBindExists\n");
/*if ( GatewaysBindExists(cp,gatewayspk,coin,tokenid) != 0 ) // dont forget to check mempool!
{
fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid));
return("");
}*/
if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2)));
}
fprintf(stderr,"cant find enough inputs\n");
return("");
}
uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,uint256 batontxid)
{
CTransaction tx; uint256 hash,mhash,hashBlock,oracletxid; int64_t val; int32_t numvouts; int64_t merkleht; CPubKey pk; std::vector<uint8_t>data;
txid = zeroid;
while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,hash,pk,data) == 'D' && oracletxid == reforacletxid )
{
if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height )
{
if ( oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()) == sizeof(hash) &&
oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()) == sizeof(hash) && mhash != zeroid )
{
txid = batontxid;
return(mhash);
} else return(zeroid);
}
batontxid = hash;
} else break;
}
return(zeroid);
}
int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vector<uint256>proof,uint256 merkleroot,std::vector<uint8_t>redeemscript)
{
uint256 hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; CScript scriptPubKey; char destaddr[64],str[65]; int32_t numvouts; int64_t nValue = 0;
if ( GetTransaction(oracletxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid));
return(0);
}
if ( DecodeOraclesCreateOpRet(tx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' || name != refcoin )
{
fprintf(stderr,"GatewaysVerify mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str());
return(0);
}
if ( DecodeHexTx(tx,deposithex) != 0 )
{
scriptPubKey = CScript() << redeemscript;
Getscriptaddress(destaddr,tx.vout[0].scriptPubKey);
if ( strcmp(refdepositaddr,destaddr) == 0 && scriptPubKey == tx.vout[1].scriptPubKey )
{
txid = tx.GetHash();
nValue = tx.vout[0].nValue;
}
else
{
Getscriptaddress(destaddr,tx.vout[1].scriptPubKey);
if ( strcmp(refdepositaddr,destaddr) == 0 && scriptPubKey == tx.vout[0].scriptPubKey )
{
txid = tx.GetHash();
nValue = tx.vout[1].nValue;
}
}
}
if ( txid == cointxid )
{
fprintf(stderr,"verify proof for cointxid in merkleroot\n");
return(nValue);
} else fprintf(stderr,"(%s) != (%s) or txid mismatch.%d or script mismatch.%d\n",refdepositaddr,destaddr,txid != cointxid,scriptPubKey != tx.vout[1].scriptPubKey);
return(0);
}
int64_t GatewaysDepositval(CTransaction tx)
{
int32_t numvouts,height; int64_t amount; std::string coin,deposithex; std::vector<CPubKey> publishers; std::vector<uint256>txids; uint256 bindtxid,cointxid; std::vector<uint256> proof; std::vector<uint8_t> claimpubkey;
if ( (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,claimpubkey,amount) == 'D' )
{
// coin, bindtxid, publishers
fprintf(stderr,"need to validate deposittxid more\n");
return(amount);
}
}
return(0);
}
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,std::vector<CPubKey>pubkeys,int32_t height,std::string refcoin,uint256 cointxid,std::string deposithex,std::vector<uint256>proof,std::vector<uint8_t> redeemscript,int64_t amount)
{
CMutableTransaction mtx; CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; int64_t totalsupply; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; std::vector<CPubKey> msigpubkeys,publishers; std::vector<uint256>txids; char str[65],depositaddr[64];
cp = CCinit(&C,EVAL_GATEWAYS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin )
{
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
return("");
}
n = (int32_t)pubkeys.size();
merkleroot = zeroid;
for (i=m=0; i<n; i++)
{
if ( (mhash= GatewaysReverseScan(txid,height,oracletxid,OraclesBatontxid(oracletxid,pubkeys[i]))) != zeroid )
{
if ( merkleroot == zeroid )
merkleroot = mhash, m = 1;
else if ( mhash == merkleroot )
m++;
publishers.push_back(pubkeys[i]);
txids.push_back(txid);
}
}
if ( merkleroot == zeroid || m < n/2 )
{
fprintf(stderr,"couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d\n",height,coin.c_str(),uint256_str(str,oracletxid),m,n);
return("");
}
if ( GatewaysVerify(depositaddr,oracletxid,coin,cointxid,deposithex,proof,merkleroot,redeemscript) != amount )
{
fprintf(stderr,"deposittxid didnt validate\n");
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,redeemscript,amount)));
}
fprintf(stderr,"cant find enough inputs\n");
return("");
}
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,std::vector<uint8_t> claimpubkey,int64_t amount)
{
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; int64_t totalsupply,depositamount,inputs,CCchange=0; int32_t numvouts; uint256 hashBlock,assetid,oracletxid; char str[65],depositaddr[64];
cp = CCinit(&C,EVAL_GATEWAYS);
assetscp = CCinit(&C2,EVAL_ASSETS);
memcpy(cp->unspendablepriv2,assetscp->CCpriv,32);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
{
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
return("");
}
if ( GetTransaction(deposittxid,tx,hashBlock,false) == 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( (depositamount= GatewaysDepositval(tx)) != amount )
{
fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN);
return("");
}
if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 )
{
if ( (inputs= AddAssetInputs(assetscp,mtx,gatewayspk,assetid,amount,60)) > 0 )
{
if ( inputs > amount )
CCchange = (inputs - amount);
mtx.vin.push_back(CTxIn(deposittxid,0,CScript()));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,gatewayspk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
}
}
fprintf(stderr,"cant find enough inputs or mismatched total\n");
return("");
}
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
{
CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C,*assetscp,C2; uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector<CPubKey> msigpubkeys; char depositaddr[64],str[65];
cp = CCinit(&C,EVAL_GATEWAYS);
assetscp = CCinit(&C2,EVAL_ASSETS);
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp,0);
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
{
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
return("");
}
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
{
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 )
{
if ( (inputs= AddAssetInputs(assetscp,mtx,mypk,assetid,amount,60)) > 0 )
{
if ( inputs > amount )
CCchange = (inputs - amount);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,gatewayspk));
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG));
return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey())));
}
}
fprintf(stderr,"cant find enough inputs or mismatched total\n");
return("");
}
// withdrawtxid used on external chain to create baton address, its existence in mempool (along with the withdraw) proof that the withdraw is pending

View File

@@ -59,7 +59,7 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &imp
// check burn amount // check burn amount
{ {
uint64_t burnAmount = burnTx.vout[0].nValue; uint64_t burnAmount = burnTx.vout.back().nValue;
if (burnAmount == 0) if (burnAmount == 0)
return Invalid("invalid-burn-amount"); return Invalid("invalid-burn-amount");
uint64_t totalOut = 0; uint64_t totalOut = 0;

76
src/cc/importpayout.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include <cryptoconditions.h>
#include "main.h"
#include "chain.h"
#include "streams.h"
#include "cc/eval.h"
#include "cc/betprotocol.h"
#include "primitives/transaction.h"
/*
* Crypto-Condition EVAL method that verifies a payout against a transaction
* notarised on another chain.
*
* IN: params - condition params
* IN: importTx - Payout transaction on value chain (KMD)
* IN: nIn - index of input of stake
*
* importTx: Spends stakeTx with payouts from asset chain
*
* in 0: Spends Stake TX and contains ImportPayout CC
* out 0: OP_RETURN MomProof, disputeTx
* out 1-: arbitrary payouts
*
* disputeTx: Spends sessionTx.0 (opener on asset chain)
*
* in 0: spends sessionTx.0
* in 1-: anything
* out 0: OP_RETURN hash of payouts
* out 1-: anything
*/
bool Eval::ImportPayout(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
{
if (importTx.vout.size() == 0) return Invalid("no-vouts");
// load data from vout[0]
MoMProof proof;
CTransaction disputeTx;
{
std::vector<unsigned char> vopret;
GetOpReturnData(importTx.vout[0].scriptPubKey, vopret);
if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx))
return Invalid("invalid-payload");
}
// Check disputeTx.0 shows correct payouts
{
uint256 givenPayoutsHash;
GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash);
std::vector<CTxOut> payouts(importTx.vout.begin() + 1, importTx.vout.end());
if (givenPayoutsHash != SerializeHash(payouts))
return Invalid("wrong-payouts");
}
// Check disputeTx spends sessionTx.0
// condition ImportPayout params is session ID from other chain
{
uint256 sessionHash;
if (!E_UNMARSHAL(params, ss >> sessionHash))
return Invalid("malformed-params");
if (disputeTx.vin[0].prevout != COutPoint(sessionHash, 0))
return Invalid("wrong-session");
}
// Check disputeTx solves momproof from vout[0]
{
NotarisationData data;
if (!GetNotarisationData(proof.notarisationHash, data))
return Invalid("coudnt-load-mom");
if (data.MoM != proof.Exec(disputeTx.GetHash()))
return Invalid("mom-check-fail");
}
return Valid();
}

View File

@@ -389,7 +389,6 @@ int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
int32_t i,j; int64_t price = 0; int32_t i,j; int64_t price = 0;
if ( n == 1 ) if ( n == 1 )
return(prices[0]); return(prices[0]);
// deterministic sort, like heapsort
for (i=0; i<n; i++) for (i=0; i<n; i++)
{ {
j = (height + i) % n; j = (height + i) % n;
@@ -401,55 +400,114 @@ int64_t correlate_price(int32_t height,int64_t *prices,int32_t n)
fprintf(stderr,"-> %llu ht.%d\n",(long long)price,height); fprintf(stderr,"-> %llu ht.%d\n",(long long)price,height);
} }
int64_t OracleCorrelatedPrice(int32_t height,char *format,std::vector <uint8_t> datas[ORACLES_MAXPROVIDERS],int32_t n) int64_t OracleCorrelatedPrice(int32_t height,std::vector <int64_t> origprices)
{ {
int64_t prices[ORACLES_MAXPROVIDERS]; int32_t i,m=0; uint256 hash; int64_t val,price=0; std::vector <int64_t> sorted; int32_t i,n; int64_t *prices,price;
if ( format[0] == 'L' ) if ( (n= origprices.size()) == 1 )
return(origprices[0]);
std::sort(origprices.begin(), origprices.end());
prices = (int64_t *)calloc(n,sizeof(*prices));
i = 0;
for (std::vector<int64_t>::const_iterator it=sorted.begin(); it!=sorted.end(); it++)
prices[i++] = *it;
price = correlate_price(height,prices,i);
free(prices);
return(price);
}
int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey pk,int32_t height,std::vector <uint8_t> data,int32_t maxheight)
{
struct oracleprice_info item; int32_t flag = 0;
for (std::vector<struct oracleprice_info>::iterator it=publishers.begin(); it!=publishers.end(); it++)
{ {
for (i=0; i<n; i++) if ( pk == it->pk )
{ {
oracle_format(&hash,&val,0,'L',(uint8_t *)datas[i].data(),0,(int32_t)datas[i].size()); flag = 1;
if ( val != 0 ) if ( height > it->height )
prices[m++] = val; {
it->height = height;
it->data = data;
return(height);
}
} }
} }
if ( m != 0 ) if ( flag == 0 )
price = correlate_price(height,prices,m); {
return(0); item.pk = pk;
item.data = data;
item.height = height;
publishers.push_back(item);
return(height);
} else return(0);
} }
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format) int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format)
{ {
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CTransaction regtx,tx; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk,providers[ORACLES_MAXPROVIDERS]; int32_t i,j,n=0; int64_t datafee; char batonaddr[64]; std::vector <uint8_t> data,datas[ORACLES_MAXPROVIDERS]; struct CCcontract_info *cp,C; 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;
if ( format[0] != 'L' )
return(0);
cp = CCinit(&C,EVAL_ORACLES); cp = CCinit(&C,EVAL_ORACLES);
SetCCunspents(unspentOutputs,markeraddr); SetCCunspents(unspentOutputs,markeraddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{ {
txid = it->first.txhash; txid = it->first.txhash;
if ( myGetTransaction(txid,regtx,hashBlock) != 0 ) ht = (int32_t)it->second.blockHeight;
if ( myGetTransaction(txid,regtx,hash) != 0 )
{ {
if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid ) if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == reforacletxid )
{ {
for (j=0; j<n; j++) Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
if ( pk == providers[j] ) batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
break; if ( batontxid != zeroid && (ht= oracleprice_add(publishers,pk,ht,data,maxheight)) > maxheight )
if ( j == n ) maxheight = ht;
}
}
}
if ( maxheight > 10 )
{
for (std::vector<struct oracleprice_info>::const_iterator it=publishers.begin(); it!=publishers.end(); it++)
{
if ( it->height >= maxheight-10 )
{
oracle_format(&hash,&price,0,'L',(uint8_t *)it->data.data(),0,(int32_t)it->data.size());
if ( price != 0 )
prices.push_back(price);
}
}
return(OracleCorrelatedPrice(height,prices));
}
return(0);
}
uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
{
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
CTransaction tx; uint256 hash,txid,rettxid,oracletxid; CPubKey pk,markerpubkey; int32_t numvouts,maxheight=0; int64_t datafee,ht; uint8_t buf33[33]; char markeraddr[64]; std::vector <uint8_t> data; struct CCcontract_info *cp,C;
rettxid = zeroid;
cp = CCinit(&C,EVAL_ORACLES);
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&reforacletxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
SetCCunspents(unspentOutputs,markeraddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
//ht = (int32_t)it->second.blockHeight;
if ( myGetTransaction(txid,tx,hash) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,hash,pk,data) == 'D' && oracletxid == reforacletxid && pk == refpk )
{
if ( oracle_format(&hash,&ht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && ht > maxheight )
{ {
Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey); maxheight = ht;
batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); rettxid = txid;
if ( batontxid != zeroid )
{
datas[n] = data;
providers[n++] = pk;
if ( n == ORACLES_MAXPROVIDERS )
break;
}
} }
} }
} }
} }
return(OracleCorrelatedPrice(height,format,datas,n)); return(rettxid);
} }
int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)

View File

@@ -33,6 +33,10 @@
it can be closed at anytime by the trader for cash settlement it can be closed at anytime by the trader for cash settlement
the house account can close it if rekt the house account can close it if rekt
Implementation Notes:
In order to eliminate the need for worrying about sybil attacks, each prices plan would be able to specific pubkey(s?) for whitelisted publishers. It would be possible to have a non-whitelisted plan that would use 50% correlation between publishers.
delta neutral balancing of risk exposure
*/ */
@@ -156,69 +160,49 @@ int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
return(totalinputs); return(totalinputs);
} }
/* #ifdef later
UniValue PriceInfo(uint256 origtxid) UniValue PricesInfo(uint256 pricesid)
{ {
UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ); UniValue result(UniValue::VOBJ); CPubKey pricepk; uint256 hashBlock,oracletxid; CTransaction vintx; int64_t minbet,maxbet,maxodds; uint64_t funding; char numstr[65]; struct CCcontract_info *cp,C;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; if ( GetTransaction(pricesid,vintx,hashBlock,false) == 0 )
CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey markerpubkey,pk; struct CCcontract_info *cp,C; uint8_t buf33[33]; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector <uint8_t> data;
cp = CCinit(&C,EVAL_ORACLES);
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&origtxid,32);
markerpubkey = buf2pk(buf33);
Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG);
if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 )
{ {
if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' ) fprintf(stderr,"cant find fundingtxid\n");
{ ERR_RESULT("cant find fundingtxid");
result.push_back(Pair("result","success")); return(result);
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("format",format));
result.push_back(Pair("marker",markeraddr));
SetCCunspents(unspentOutputs,markeraddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,regtx,hashBlock,false) != 0 )
{
if ( regtx.vout.size() > 0 && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,oracletxid,pk,datafee) == 'R' && oracletxid == origtxid )
{
obj.push_back(Pair("provider",pubkey33_str(str,(uint8_t *)pk.begin())));
Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey);
batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data);
obj.push_back(Pair("baton",batonaddr));
obj.push_back(Pair("batontxid",uint256_str(str,batontxid)));
funding = LifetimeOraclesFunds(cp,oracletxid,pk);
sprintf(numstr,"%.8f",(double)funding/COIN);
obj.push_back(Pair("lifetime",numstr));
funding = AddOracleInputs(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));
}
} }
if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,oracletxid,minbet,maxbet,maxodds) == 0 )
{
fprintf(stderr,"fundingtxid isnt price creation txid\n");
ERR_RESULT("fundingtxid isnt price creation txid");
return(result);
}
result.push_back(Pair("result","success"));
result.push_back(Pair("pricesid",uint256_str(str,pricesid)));
result.push_back(Pair("oracletxid",uint256_str(str,oracletxid)));
sprintf(numstr,"%.8f",(double)minbet/COIN);
result.push_back(Pair("minbet",numstr));
sprintf(numstr,"%.8f",(double)maxbet/COIN);
result.push_back(Pair("maxbet",numstr));
result.push_back(Pair("maxodds",maxodds));
cp = CCinit(&C,EVAL_PRICES);
pricepk = GetUnspendable(cp,0);
funding = PricePlanFunds(cp,pricepk,pricesid);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
return(result); return(result);
} }
UniValue PricesList() UniValue PricesList()
{ {
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]; UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid; CTransaction vintx; int64_t minbet,maxbet,maxodds; char str[65];
cp = CCinit(&C,EVAL_ORACLES); cp = CCinit(&C,EVAL_PRICES);
SetCCtxids(addressIndex,cp->normaladdr); SetCCtxids(addressIndex,cp->normaladdr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
{ {
txid = it->first.txhash; txid = it->first.txhash;
if ( GetTransaction(txid,createtx,hashBlock,false) != 0 ) if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{ {
if ( createtx.vout.size() > 0 && DecodeOraclesCreateOpRet(createtx.vout[createtx.vout.size()-1].scriptPubKey,name,description,format) == 'C' ) if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,oracletxid,minbet,maxbet,maxodds) != 0 )
{ {
result.push_back(uint256_str(str,txid)); result.push_back(uint256_str(str,txid));
} }
@@ -226,4 +210,127 @@ UniValue PricesList()
} }
return(result); return(result);
} }
*/
std::string PricesCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
{
CMutableTransaction mtx; uint256 zero; CScript fundingPubKey; CPubKey mypk,pricepk; int64_t a,b,c,d; uint64_t sbits; struct CCcontract_info *cp,C;
if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || maxodds > 9999 || timeoutblocks < 0 || timeoutblocks > 1440 )
{
CCerror = "invalid parameter error";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( funds < 100*COIN )
{
CCerror = "price plan needs at least 100 coins";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
memset(&zero,0,sizeof(zero));
if ( (cp= Pricesinit(fundingPubKey,zero,&C,planstr,txfee,mypk,pricepk,sbits,a,b,c,d)) == 0 )
{
CCerror = "Priceinit error in create funding";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( AddNormalinputs(mtx,mypk,funds+3*txfee,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,pricepk));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricepk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',sbits,minbet,maxbet,maxodds,timeoutblocks)));
}
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
std::string PricesAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
{
CMutableTransaction mtx; CScript fundingPubKey,scriptPubKey; CPubKey mypk,pricepk; struct CCcontract_info *cp,C; int64_t minbet,maxbet,maxodds;
if ( amount < 0 )
{
CCerror = "amount must be positive";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( (cp= Pricesinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,pricepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
return("");
scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
if ( scriptPubKey == fundingPubKey )
{
if ( AddNormalinputs(mtx,mypk,amount+2*txfee,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,pricepk));
mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesOpRet('E',sbits,fundingtxid,hentropy,zeroid)));
}
else
{
CCerror = "cant find enough inputs";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
}
else
{
CCerror = "only fund creator can add more funds (entropy)";
fprintf(stderr,"%s\n", CCerror.c_str() );
}
return("");
}
std::string PricesBet(uint64_t txfee,uint256 pricesid,int64_t bet,int32_t odds)
{
CMutableTransaction mtx; CScript fundingPubKey; CPubKey mypk,pricepk; int64_t funding,minbet,maxbet,maxodds; struct CCcontract_info *cp,C;
if ( bet < 0 )
{
CCerror = "bet must be positive";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( odds < 1 || odds > 9999 )
{
CCerror = "odds must be between 1 and 9999";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( (cp= Pricesinit(fundingPubKey,pricesid,&C,txfee,mypk,pricepk,minbet,maxbet,maxodds)) == 0 )
return("");
if ( bet < minbet || bet > maxbet || odds > maxodds )
{
CCerror = strprintf("Price plan %s illegal bet %.8f: minbet %.8f maxbet %.8f or odds %d vs max.%d\n",planstr,(double)bet/COIN,(double)minbet/COIN,(double)maxbet/COIN,(int32_t)odds,(int32_t)maxodds);
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( (funding= PricesPlanFunds(cp,pricepk,pricesid)) >= 2*bet*odds+txfee )
{
if ( myIsutxo_spentinmempool(entropytxid,0) != 0 )
{
CCerror = "entropy txid is spent";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,pricepk));
mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,pricepk));
mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesOpRet('B',pricesid)));
} else fprintf(stderr,"cant find enough normal inputs for %.8f, plan funding %.8f\n",(double)bet/COIN,(double)funding/COIN);
}
if ( entropyval == 0 && funding != 0 )
CCerror = "cant find price entropy inputs";
else CCerror = "cant find price input";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
std::string PricesBetFinish(int32_t *resultp,uint64_t txfee,uint256 pricesid,uint256 bettxid)
{
*resultp = -1;
CCerror = "couldnt find bettx or entropytx";
fprintf(stderr,"%s\n", CCerror.c_str() );
return("");
}
#endif

View File

@@ -50,6 +50,8 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh
int seenOwnNotarisations = 0; int seenOwnNotarisations = 0;
bool txscl = IsTXSCL(symbol);
for (int i=0; i<NOTARISATION_SCAN_LIMIT_BLOCKS; i++) { for (int i=0; i<NOTARISATION_SCAN_LIMIT_BLOCKS; i++) {
if (i > kmdHeight) break; if (i > kmdHeight) break;
NotarisationsInBlock notarisations; NotarisationsInBlock notarisations;
@@ -72,8 +74,9 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh
if (seenOwnNotarisations == 1) { if (seenOwnNotarisations == 1) {
BOOST_FOREACH(Notarisation& nota, notarisations) { BOOST_FOREACH(Notarisation& nota, notarisations) {
if (nota.second.ccId == targetCCid) if (IsTXSCL(nota.second.symbol) == txscl)
moms.push_back(nota.second.MoM); if (nota.second.ccId == targetCCid)
moms.push_back(nota.second.MoM);
} }
} }
} }

2
src/fiat/vote2018 Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
./komodo-cli -ac_name=VOTE2018 $1 $2 $3 $4 $5 $6

View File

@@ -45,7 +45,7 @@ bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint
{ {
std::vector<uint8_t> burnOpret; std::vector<uint8_t> burnOpret;
if (burnTx.vout.size() == 0) return false; if (burnTx.vout.size() == 0) return false;
GetOpReturnData(burnTx.vout[0].scriptPubKey, burnOpret); GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret);
return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid);
ss >> targetSymbol; ss >> targetSymbol;
ss >> payoutsHash); ss >> payoutsHash);
@@ -61,7 +61,7 @@ CAmount GetCoinImportValue(const CTransaction &tx)
CTransaction burnTx; CTransaction burnTx;
std::vector<CTxOut> payouts; std::vector<CTxOut> payouts;
if (UnmarshalImportTx(tx, proof, burnTx, payouts)) { if (UnmarshalImportTx(tx, proof, burnTx, payouts)) {
return burnTx.vout.size() ? burnTx.vout[0].nValue : 0; return burnTx.vout.size() ? burnTx.vout.back().nValue : 0;
} }
return 0; return 0;
} }

View File

@@ -1552,14 +1552,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
KOMODO_ON_DEMAND++; KOMODO_ON_DEMAND++;
pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
// Add memory address index if (!tx.IsCoinImport())
if (fAddressIndex) { {
pool.addAddressIndex(entry, view); // Add memory address index
} if (fAddressIndex) {
pool.addAddressIndex(entry, view);
}
// Add memory spent index // Add memory spent index
if (fSpentIndex) { if (fSpentIndex) {
pool.addSpentIndex(entry, view); pool.addSpentIndex(entry, view);
}
} }
} }

View File

@@ -26,7 +26,7 @@ NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight)
{ {
NotarisationData data; NotarisationData data;
if (ParseNotarisationOpReturn(tx, data)) if (ParseNotarisationOpReturn(tx, data))
if (strlen(data.symbol) >= 5 && strncmp(data.symbol, "TXSCL", 5) == 0) if (IsTXSCL(data.symbol))
isTxscl = 1; isTxscl = 1;
} }
@@ -46,6 +46,11 @@ NotarisationsInBlock ScanBlockNotarisations(const CBlock &block, int nHeight)
return vNotarisations; return vNotarisations;
} }
bool IsTXSCL(const char* symbol)
{
return strlen(symbol) >= 5 && strncmp(symbol, "TXSCL", 5) == 0;
}
bool GetBlockNotarisations(uint256 blockHash, NotarisationsInBlock &nibs) bool GetBlockNotarisations(uint256 blockHash, NotarisationsInBlock &nibs)
{ {

View File

@@ -24,5 +24,6 @@ bool GetBackNotarisation(uint256 notarisationHash, Notarisation &n);
void WriteBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch); void WriteBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch);
void EraseBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch); void EraseBackNotarisations(const NotarisationsInBlock notarisations, CLevelDBBatch &batch);
int ScanNotarisationsDB(int height, std::string symbol, int scanLimitBlocks, Notarisation& out); int ScanNotarisationsDB(int height, std::string symbol, int scanLimitBlocks, Notarisation& out);
bool IsTXSCL(const char* symbol);
#endif /* NOTARISATIONDB_H */ #endif /* NOTARISATIONDB_H */

View File

@@ -303,6 +303,8 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "paxpending", &paxpending, true }, { "blockchain", "paxpending", &paxpending, true },
{ "blockchain", "paxprices", &paxprices, true }, { "blockchain", "paxprices", &paxprices, true },
{ "blockchain", "notaries", &notaries, true }, { "blockchain", "notaries", &notaries, true },
//{ "blockchain", "height_MoM", &height_MoM, true },
//{ "blockchain", "txMoMproof", &txMoMproof, true },
{ "blockchain", "minerids", &minerids, true }, { "blockchain", "minerids", &minerids, true },
{ "blockchain", "kvsearch", &kvsearch, true }, { "blockchain", "kvsearch", &kvsearch, true },
{ "blockchain", "kvupdate", &kvupdate, true }, { "blockchain", "kvupdate", &kvupdate, true },
@@ -409,6 +411,12 @@ static const CRPCCommand vRPCCommands[] =
/* Gateways */ /* Gateways */
{ "gateways", "gatewaysaddress", &gatewaysaddress, true }, { "gateways", "gatewaysaddress", &gatewaysaddress, true },
{ "gateways", "gatewayslist", &gatewayslist, true },
{ "gateways", "gatewaysinfo", &gatewaysinfo, true },
{ "gateways", "gatewaysbind", &gatewaysbind, true },
{ "gateways", "gatewaysdeposit", &gatewaysdeposit, true },
{ "gateways", "gatewaysclaim", &gatewaysclaim, true },
{ "gateways", "gatewayswithdraw", &gatewayswithdraw, true },
/* dice */ /* dice */
{ "dice", "dicelist", &dicelist, true }, { "dice", "dicelist", &dicelist, true },

View File

@@ -236,7 +236,14 @@ extern UniValue pegsaddress(const UniValue& params, bool fHelp);
extern UniValue triggersaddress(const UniValue& params, bool fHelp); extern UniValue triggersaddress(const UniValue& params, bool fHelp);
extern UniValue paymentsaddress(const UniValue& params, bool fHelp); extern UniValue paymentsaddress(const UniValue& params, bool fHelp);
extern UniValue gatewaysaddress(const UniValue& params, bool fHelp); extern UniValue gatewaysaddress(const UniValue& params, bool fHelp);
extern UniValue gatewayslist(const UniValue& params, bool fHelp);
extern UniValue gatewaysinfo(const UniValue& params, bool fHelp);
extern UniValue gatewaysbind(const UniValue& params, bool fHelp);
extern UniValue gatewaysdeposit(const UniValue& params, bool fHelp);
extern UniValue gatewaysclaim(const UniValue& params, bool fHelp);
extern UniValue gatewayswithdraw(const UniValue& params, bool fHelp);
extern UniValue channelsinfo(const UniValue& params, bool fHelp); extern UniValue channelsinfo(const UniValue& params, bool fHelp);
extern UniValue channelsbind(const UniValue& params, bool fHelp);
extern UniValue channelsopen(const UniValue& params, bool fHelp); extern UniValue channelsopen(const UniValue& params, bool fHelp);
extern UniValue channelspayment(const UniValue& params, bool fHelp); extern UniValue channelspayment(const UniValue& params, bool fHelp);
extern UniValue channelscollect(const UniValue& params, bool fHelp); extern UniValue channelscollect(const UniValue& params, bool fHelp);

View File

@@ -180,7 +180,7 @@ TEST_F(TestCoinImport, testInvalidBurnOutputs)
TEST_F(TestCoinImport, testInvalidBurnParams) TEST_F(TestCoinImport, testInvalidBurnParams)
{ {
burnTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid)); burnTx.vout.back().scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid));
MoMoM = burnTx.GetHash(); // TODO: an actual branch MoMoM = burnTx.GetHash(); // TODO: an actual branch
CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
TestRunCCEval(tx); TestRunCCEval(tx);
@@ -198,7 +198,7 @@ TEST_F(TestCoinImport, testWrongChainId)
TEST_F(TestCoinImport, testInvalidBurnAmount) TEST_F(TestCoinImport, testInvalidBurnAmount)
{ {
burnTx.vout[0].nValue = 0; burnTx.vout.back().nValue = 0;
MoMoM = burnTx.GetHash(); // TODO: an actual branch MoMoM = burnTx.GetHash(); // TODO: an actual branch
CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts); CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
TestRunCCEval(tx); TestRunCCEval(tx);

View File

@@ -4857,6 +4857,7 @@ int32_t ensure_CCrequirements()
#include "../cc/CClotto.h" #include "../cc/CClotto.h"
#include "../cc/CCchannels.h" #include "../cc/CCchannels.h"
#include "../cc/CCOracles.h" #include "../cc/CCOracles.h"
#include "../cc/CCGateways.h"
UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey) UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey)
{ {
@@ -4875,6 +4876,11 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned ch
result.push_back(Pair(str,cp->unspendableCCaddr)); result.push_back(Pair(str,cp->unspendableCCaddr));
sprintf(str,"%smarker",name); sprintf(str,"%smarker",name);
result.push_back(Pair(str,cp->normaladdr)); result.push_back(Pair(str,cp->normaladdr));
if ( _GetCCaddress(destaddr,EVAL_ASSETS,pubkey2pk(pubkey)) > 0 )
{
sprintf(str,"%sCCassets",name);
result.push_back(Pair(str,destaddr));
}
if ( pubkey.size() == 33 ) if ( pubkey.size() == 33 )
{ {
if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 ) if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
@@ -5386,6 +5392,94 @@ UniValue rewardsinfo(const UniValue& params, bool fHelp)
return(RewardsInfo(fundingtxid)); return(RewardsInfo(fundingtxid));
} }
UniValue gatewayslist(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() > 0 )
throw runtime_error("gatewayslist\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
return(GatewaysList());
}
UniValue gatewaysinfo(const UniValue& params, bool fHelp)
{
uint256 txid;
if ( fHelp || params.size() != 1 )
throw runtime_error("gatewaysinfo bindtxid\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
txid = Parseuint256((char *)params[0].get_str().c_str());
return(GatewaysInfo(txid));
}
UniValue gatewaysbind(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 tokenid,oracletxid; int32_t i; int64_t totalsupply; std::vector<CPubKey> pubkeys; uint8_t M,N; std::string hex,coin; std::vector<unsigned char> pubkey;
if ( fHelp || params.size() < 6 )
throw runtime_error("gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s)\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
tokenid = Parseuint256((char *)params[0].get_str().c_str());
oracletxid = Parseuint256((char *)params[1].get_str().c_str());
coin = params[2].get_str();
totalsupply = atol((char *)params[3].get_str().c_str());
M = atoi((char *)params[4].get_str().c_str());
N = atoi((char *)params[5].get_str().c_str());
if ( M > N || N == 0 || N > 15 || totalsupply < COIN/100 || tokenid == zeroid )
throw runtime_error("illegal M or N > 15 or tokensupply or invalid tokenid\n");
pubkeys.resize(N);
for (i=0; i<N; i++)
{
if ( params.size() < 5+i+1 )
throw runtime_error("not enough parameters for N pubkeys\n");
pubkey = ParseHex(params[5+i].get_str().c_str());
pubkeys.push_back(pubkey2pk(pubkey));
}
hex = GatewaysBind(0,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewaysbind");
return(result);
}
UniValue gatewaysdeposit(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex;
//std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,std::vector<CPubKey>pubkeys,int32_t height,std::string refcoin,uint256 cointxid,std::string deposithex,std::vector<uint256>proof,std::vector<uint8_t> claimpubkey,int64_t amount)
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewaysdeposit");
return(result);
}
UniValue gatewaysclaim(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex;
// std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string coin,uint256 deposittxid,std::string claimaddr,int64_t amount)
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewaysclaim");
return(result);
}
UniValue gatewayswithdraw(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex;
// std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector<uint8_t> withdrawpub,int64_t amount)
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
} else ERR_RESULT("couldnt gatewayswithdraw");
return(result);
}
UniValue oracleslist(const UniValue& params, bool fHelp) UniValue oracleslist(const UniValue& params, bool fHelp)
{ {
if ( fHelp || params.size() > 0 ) if ( fHelp || params.size() > 0 )

View File

@@ -2,7 +2,11 @@
set -eu set -eu
PARAMS_DIR="$HOME/.zcash-params" if [[ "$OSTYPE" == "darwin"* ]]; then
PARAMS_DIR="$HOME/Library/Application Support/ZcashParams"
else
PARAMS_DIR="$HOME/.zcash-params"
fi
SPROUT_PKEY_NAME='sprout-proving.key' SPROUT_PKEY_NAME='sprout-proving.key'
SPROUT_VKEY_NAME='sprout-verifying.key' SPROUT_VKEY_NAME='sprout-verifying.key'