diff --git a/resolve.sh b/resolve.sh new file mode 100755 index 000000000..548e71dee --- /dev/null +++ b/resolve.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +for f in $(git diff --name-only --diff-filter=U | cat); do + echo "Resolve conflict in $f ..." + git checkout --theirs $f +done + +for f in $(git diff --name-only --diff-filter=U | cat); do + echo "Adding file $f ..." + git add $f +done + diff --git a/src/ac/mgnx b/src/ac/mgnx new file mode 100755 index 000000000..9bd85336e --- /dev/null +++ b/src/ac/mgnx @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=MGNX $1 $2 $3 $4 $5 $6 diff --git a/src/ac/pirate b/src/ac/pirate new file mode 100755 index 000000000..9314209da --- /dev/null +++ b/src/ac/pirate @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=PIRATE $1 $2 $3 $4 $5 $6 diff --git a/src/assetchains.old b/src/assetchains.old index 158e62cad..fcee4bf41 100755 --- a/src/assetchains.old +++ b/src/assetchains.old @@ -39,3 +39,5 @@ echo $pubkey ~/VerusCoin/src/komodod -pubkey=$pubkey -ac_name=VRSC -ac_algo=verushash -ac_cc=1 -ac_veruspos=50 -ac_supply=0 -ac_eras=3 -ac_reward=0,38400000000,2400000000 -ac_halving=1,43200,1051920 -ac_decay=100000000,0,0 -ac_end=10080,226080,0 -ac_timelockgte=19200000000 -ac_timeunlockfrom=129600 -ac_timeunlockto=1180800 -addnode=185.25.48.236 -addnode=185.64.105.111 & ./komodod -pubkey=$pubkey -ac_name=SEC -ac_cc=333 -ac_supply=1000000000 -addnode=185.148.145.43 & ./komodod -pubkey=$pubkey -ac_name=CCL -ac_supply=200000000 -ac_end=1 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=142.93.136.89 -addnode=195.201.22.89 & +./komodod -pubkey=$pubkey -ac_name=PIRATE -ac_supply=0 -ac_reward=25600000000 -ac_halving=77777 -ac_private=1 -addnode=136.243.102.225 & +./komodod -pubkey=$pubkey -ac_name=MGNX -ac_supply=12465003 -ac_staked=90 -ac_reward=2000000000 -ac_halving=525960 -ac_cc=2 -ac_end=2629800 -addnode=142.93.27.180 & diff --git a/src/cc/CC made easy b/src/cc/CC made easy index 4158e061e..895d84404 100644 --- a/src/cc/CC made easy +++ b/src/cc/CC made easy @@ -447,7 +447,51 @@ WARNING: there is an attack vector that precludes betting any large amounts, it In order to mitigate this, the disclosure of the house entropy needs to be delayed beyond a reasonable reorg depth (notarization). It is recommended for production dice game with significant amounts of money to use such a delayed disclosure method. -Chapter 10 - lotto example +Chapter 10 - channels example +It might be hard to believe, but channels CC implements an instant payment mechanism that is secured by dPoW in a way that is backward compatible with the existing wallets, explorers, etc. and channels CC does not require both nodes to be online. Its usecases are all the usecases for Lightning Network, it is just more secure, less expensive and backward compatible! The one aspect which some might consider a downside (and others another benefit) is that all payments are onchain. This means it would increase blockchain size, but the idea is for channels CC to be used on blockchains with relatively lower value coins, so a txfee of 0.0001 is not anything significant. + +Warning: very confusing blockchain reorganization issues described below. Will be confusing to most people + +From a distance, the blockchain is a chain of blocks. One block after the next, each referencing all the prior blocks. Each block containing a group of transactions. Prior to getting into a block, the transactions are broadcast to the network and if it is valid, it enters the memory pool. Each miner then constructs a valid block from these memory pool transactions and when a transaction gets mined (confirmed), it is removed from the memory pool. + +That is the simple version! + +The reality is quite a bit more complex, but the critical aspect is that the blockchain can (and is) reorganized as part of the expected protocol. This can happen even when there is no 51% attack happening and it is important to understand this process in detail, so here goes. + +What happens if two miners find a valid block at the same time? In this case the "same time" means within the time it takes for a block to propagate to the network. When a miner finds a new block, it is broadcast to the network and nodes update and start waiting for the next block. When there are two different (and valid) blocks propagating at the same time, some nodes update with one of the blocks and some the other, lets call it blockA and blockB. Now the nodes will know about both blockA and blockB, but some will consider blockA to be the chaintip and others will consider blockB to be the chaintip. + +This is where it gets confusing. Which is the correct chaintip (latest block?). It turns out that both blockA and blockB are valid at this moment in time. So there are actuall two blockchains. We have what is called a small fork! Now dont worry, the protocol will help us converge to a single chain, but in order to do that, we need the next block. + +Some miners will be mining from blockA and others from blockB. In most all cases, when the next block is found, it wont be at the "same time" again. So we will end up with a chain that is blockA+blockA2 or blockB+blockB2. Here comes the small reorg! Let's assuming blockA2 was found before blockB2, so that means all nodes that had blockB as the chaintip now see a longer chain blockA+blockA2, which trumps blockB. When that happens, it reorgs the chain so it is on blockA+blockA2. To do this properly, all the transactions that were in blockB are put back into the mempool and blockA is added, then blockA2. + +Of course, when blockB2 arrives, the nodes see it but blockB+blockB2 is the same length as blockA+blockA2, so no reorg happens. Since we postulated that blockAs arrived "before" blockB2, that means all nodes are on the same chaintip, including all the miners and the next block found would be blockA3, without any complications. + +Believe it or not, this sort of thing is happening all the time, one all blockchains. The chaintip is a volatile thing and that is why more than one confirmation is needed to avoid the small reorgs invalidating blockhash. However, it is possible for more than just the blockhash to change. When the reorg happens, all the transactions in the block are put back into the mempool and then the new blocks are processed in order. So what happens if one of the inputs to a transaction that happened in blockB, gets spent in blockA2? Based on random utxo allocation by wallets this is not impossible if an address has a lot of activity, but if it is part of a 51% attack, then this remote chance of an utxo being spent becomes a certainity! In fact, that is what a 51% attack is. + +The attack can go much deeper than just one block. For chains that use the longest chain rule, it can go quite deep indeed. So as all the reorged transactions are put back into the mempool, we feel good that it will get confirmed again. Unfortunately, there is no enforcement of a miner needing to mine any specific transaction in the mempool. And the 51% attacker is intent on mining the transaction that spends an already spent utxo in the reorganized chain. it is called a double spend, but in the reorganized chain, it is spent only once. So it is a bit of a misnomer. + +The important thing to understand is that if any transaction has inputs that are signed by a node, it is possible when the chain reorganizes for that transaction to become invalid. This is why dPoW is important as it doesnt strictly use the longest chain rule, but rather the longest notarized chain rule. Once a block is notarized, then it will refuse to reorganize that block (or any block before). So the risk is still there, but only until a notarization. Please see more detailed information about dPoW . + +Given the above, if you are wondering how can it be possible to have a mempool payment be secured by dPoW. Since it is explained how the reorgs can make valid transactions disappear, it seems unlikely any such solution is possible. However, the CC is very powerful and it can make unlikely things possible. + +The following describes how. + +We know that any payment that is utxo based can be invalidated via 51% attack, or even an unlikely but not impossible random utxo allocation from a busy wallet. Which means the payment cant be via a utxo. Since the CC system is utxo based, you might think that it means CC cant solve this. However, CC is very powerful and can implement payments that are not utxo based. But before this non-utxo payment method is explained, first we need to solve the mechanics of payment. + +At a high level, we want to lock funds into a channel, have this lock notarized so it cant be reorganized. Then payments can unlock funds. Additionally, if we are restricting the payment to just one destination, we also need a way for the sender to reclaim the unused funds. So there needs a way for a close channel notification, which when notarized allows the sender to reclaim all funds. After the channel close is notarized, then the only action possible should be a reclaim of sender funds. + +We need to assume that any payment, channel close, reclaim can be reorganized until it is notarized so great care needs to be made that a payment that is made will always be valid. With some allowances for blocks after a channelclose is notarized, we can protect the payments using the logic of "stop accepting payments after a channelclose is seen". It might be that a full notarization of wait time after the channelclose is notarized is needed to provide sufficient time for all the payments to be reprocessed. + +Now we can finally describe the requirements for the CC. The locked funds need to be able to be spent by either the sender or receiver, the former only after sufficient time after a channelclose and the latter only after a payment is seen (not just confirmed, but just seeing it should be enough). The protection from reorgs is that the payment itself reveals a secret that is needed for the payment and only the secret would be needed, so it wont matter what utxo is used. To lock funds into a CC address that can handle this we need a 1of2 CC address, which can accept a signature from either of two pubkeys. The additional CC constraints would be enforced to make sure payments are made until the channel is closed. + +A hashchain has the nice property of being able to encode a lot of secrets with a single hash. You can hash the hash, over and over and the final hash is the public value. By revealing the next to last hash, it can be verified that it hashes to the final hash. There is a restriction that a hashchain needs to be of reasonable maximum depth, say 1000. That means each iteration of the hashchain that is revealed is worth 1/1000th the total channelfunds. In fact, if the 500th hash value is revealed, half the channelfunds are released. this allows 1/1000th resolution that can be released with a single hash value. + +Now we can make the payment based on the hashvalue revealed at a specified depth before the prior released hashchain value. Both the sender and receiver can make a payment to the destination by attaching a hashchain secret. This means even if the sender's payment is reorganized, if the destination has the revealed secret, a replacement payment can be made that is valid. If the destination account isnt monitoring the blockchain, then it wont see the revealed secret, but in this case there shouldnt be value released for the payments that are reorganized. So it would be a case of no harm, no foul. In any event, all the payments end up verifiable on the blockchain to provide verifiability. + +Payments at the speed of the mempool, protected by dPoW! + +
+ 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. @@ -582,6 +626,39 @@ Conclusion I hope this document has helped you understand what a Komodo utxo based CC contract is and how it is different from the other smart contracts. If you are now able to dive into the cc directory and start making your own CC contract, then I am very happy! +gateways CC +gateways CC is the first CC that combines multiple CC into a single one. In order to achieve its goals, both the assets CC and the oracles CC is used, in addition to a dapp that issues regular transactions. This general approach can be used to solve quite a few different use cases, so it is important to understand how a multi-CC solution is put together. There are some tricky issues that only arise when using more than one CC at a time. + +Before the implementation details, first lets understand what the gateways CC does. At a high level it is similar to the old multigateway (from NXT AE 2014), but with improvements. The basic idea is to tokenize other crypto coins (like BTC) and then use the assets CC to transact/swap against the tokenized crypto. By enforcing a 1:1 peg between a specific token and BTC and an automated deposit/withdraw mechanism, it is possible to transact in the virtual BTC without the delay or expensive txfees. Then anybody that ends up having any of the BTC token would be able to withdraw actual BTC by redeeming the token. + +BTC -> deposit to special address -> receive token that represents BTC onchain +do onchain transactions with the BTC token +anybody who obtains the BTC token can redeem the token and get actual BTC in the withdraw address + +By bringing the operations onchain, it avoids the need for crosschain complications for each trade. The crosschain does still have to happen on the deposit and withdraw, but that is all. There is just one aspect that makes it not fully decentralized, which is the reliance on MofN multisig. However, with N trusted community members and a reasonable M value, it is not expected to be a big barrier. Since all operations are automated, the only trust needed is that M of the N multisig signers are running their nodes with the gateways dapp active and also that M of them wont collude to steal the funds locked in the multisig. In three years of operations, the MGW multigateway didnt have any incident of multisig signer misbehavior and it was only 2of3 multisig. + +How can the gatewaysCC work? First, it needs a dedicated token that can be used to represent the external crypto coin. In order to avoid any issues with misplaced tokens, it is simplest to require that 100% of all the tokens are all locked in the gatewaysCC address. We want to make it so that the only way the tokens can be released from the locked address is when a verified deposit is made. So, we also need a deposit address, which means there needs to be a set of pubkeys that control the deposit address. It turns out, we also need to post merkleroot data from the external coin so that the information is onchain to be able to validate the external deposit. Since we are already trusting the deposit address signers to safekeep the external coins via MofN multisig, trusting them to post the merkleroots doesnt increase the trust footprint needed. + +Now we have all the ingredients needed, a dedicated token, a set of multisig pubkeys and an oracle for merkleroots. + +gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s) + +With a gatewaysbind, a new gateway is defined. the pubkeys are for the custodians of the multisig funds and they also need to be posting merkleroots to the chain, so the oracle needs to be setup and funded and each of the signers needs to run the oraclefeed dapp. That posts each new merkleroot via oraclesdata and also responds to withdraw requests. + +The MofN pubkeys generates a deposit address and when funds are sent to that address along with a small amount to the claim address. With the txid from this external coin, along with the txproof and the rawtransaction, all is submitted with a gatewaysdeposit. This adds a special baton output which is a gateways CC output to invoke gateways validation and also prevents double claims by using the unspent status of the baton. + +gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount +gatewaysclaim bindtxid coin deposittxid destpub amount + +Once the gatewaysdeposit is validated, it can be claimed and now the token is sent to the claim address. A 1:1 pegging of the external crypto to the token is established. And as long as one of the deposit address signers is running the oraclefeed, then the deposit/claim process is fully automatic and under the control of the depositor. Nothing needs to be signed by any other party! Also by using the utxo from the deposittxid, double claims are prevented. + +On the withdraw side, the tokens are sent back to the address where the tokens are locked and this needs to create a redemption right that can only be used once. + +gatewayswithdraw bindtxid coin withdrawpub amount + + +And with a bit more magic in the oraclefeed, this is achieved. To be continued... + diff --git a/src/cc/CCGateways.h b/src/cc/CCGateways.h index 1b7852725..b584ba5d0 100644 --- a/src/cc/CCGateways.h +++ b/src/cc/CCGateways.h @@ -18,10 +18,19 @@ #define CC_GATEWAYS_H #include "CCinclude.h" +#include "../merkleblock.h" 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 pubkeys); +std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount); +std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount); +std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector withdrawpub,int64_t amount); +UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin); +std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid); +std::string GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr); // CCcustom -UniValue GatewaysInfo(); +UniValue GatewaysInfo(uint256 bindtxid); +UniValue GatewaysList(); #endif diff --git a/src/cc/CCOracles.h b/src/cc/CCOracles.h index bddb9b15b..41409d5c5 100644 --- a/src/cc/CCOracles.h +++ b/src/cc/CCOracles.h @@ -19,8 +19,6 @@ #include "CCinclude.h" -#define ORACLES_MAXPROVIDERS 64 - 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 OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee); diff --git a/src/cc/CCPrices.h b/src/cc/CCPrices.h index 8b09e9267..f375ee10a 100644 --- a/src/cc/CCPrices.h +++ b/src/cc/CCPrices.h @@ -22,6 +22,13 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); // CCcustom -UniValue PricesInfo(); +UniValue PricesList(); +UniValue PricesInfo(uint256 fundingtxid); +UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid); +std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector pubkeys); +std::string PricesAddFunding(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount); +std::string PricesBet(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount,int32_t leverage); +std::string PricesFinish(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,uint256 bettxid); + #endif diff --git a/src/cc/CCassets.h b/src/cc/CCassets.h index 9a0f2a0ea..4d4f30b3b 100644 --- a/src/cc/CCassets.h +++ b/src/cc/CCassets.h @@ -54,6 +54,8 @@ UniValue AssetInfo(uint256 tokenid); UniValue AssetList(); std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description); std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total); +std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode); + std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal); std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid); std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount); diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index a9361ede4..c9b975c3c 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -354,7 +354,7 @@ int64_t IsAssetvout(int64_t &price,std::vector &origpubkey,const CTrans return(0); if ( (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 ) { - fprintf(stderr,"null decodeopret\n"); + fprintf(stderr,"null decodeopret v.%d\n",v); return(0); } else if ( funcid == 'c' ) @@ -367,7 +367,10 @@ int64_t IsAssetvout(int64_t &price,std::vector &origpubkey,const CTrans else if ( funcid != 'E' ) { if ( assetid == refassetid ) + { + //fprintf(stderr,"returning %.8f\n",(double)nValue/COIN); return(nValue); + } } else if ( funcid == 'E' ) { @@ -447,7 +450,7 @@ int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpp bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid) { - CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t assetoshis; std::vector tmporigpubkey; int64_t tmpprice; + CTransaction vinTx; uint256 hashBlock,id,id2; int32_t i,flag,numvins,numvouts; int64_t assetoshis; std::vector tmporigpubkey; int64_t tmpprice; numvins = tx.vin.size(); numvouts = tx.vout.size(); inputs = outputs = 0; @@ -465,8 +468,20 @@ bool AssetExactAmounts(struct CCcontract_info *cp,int64_t &inputs,int32_t starti fprintf(stderr,"vin%d %llu, ",i,(long long)assetoshis); inputs += assetoshis; } + else + { + if ( vinTx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 && DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid ) + { + assetoshis = vinTx.vout[i].nValue; + fprintf(stderr,"vin%d %llu special case, ",i,(long long)assetoshis); + inputs += assetoshis; + } + } } } + if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid ) + flag = 1; + else flag = 0; for (i=0; i origpubkey; CTransaction vintx; int32_t j,vout,n = 0; + char coinaddr[64],destaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t j,vout,n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; @@ -32,6 +33,10 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK continue; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { + Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey); + if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) + continue; + fprintf(stderr,"check %s %.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN); if ( (nValue= IsAssetvout(price,origpubkey,vintx,vout,assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) { if ( total != 0 && maxinputs != 0 ) @@ -223,21 +228,47 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector des for (i=0; i 0 ) - { - if ( inputs > total ) - CCchange = (inputs - total); - //for (i=0; i 0 ) + { + if ( inputs > total ) + CCchange = (inputs - total); + //for (i=0; i destpubkey,int64_t total,int32_t evalcode) +{ + CMutableTransaction mtx; CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C; + if ( total < 0 ) + { + fprintf(stderr,"negative total %lld\n",(long long)total); + return(""); + } + cp = CCinit(&C,EVAL_ASSETS); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + { + if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,total,60)) > 0 ) + { + if ( inputs > total ) + CCchange = (inputs - total); + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); + mtx.vout.push_back(MakeCC1vout(evalcode,total,pubkey2pk(destpubkey))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey()))); + } else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN); + } + return(""); +} + std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal) { CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector origpubkey; std::string name,description; diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 6cf32b1c5..7ac0bfb98 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -67,15 +67,22 @@ struct CC_utxo struct CCcontract_info { uint256 prevtxid; - char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64]; - uint8_t CCpriv[32],unspendablepriv2[32]; - CPubKey unspendablepk2; + char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64],unspendableaddr3[64]; + uint8_t CCpriv[32],unspendablepriv2[32],unspendablepriv3[32]; + CPubKey unspendablepk2,unspendablepk3; bool (*validate)(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); bool (*ismyvin)(CScript const& scriptSig); - uint8_t evalcode,didinit; + uint8_t evalcode,evalcode2,evalcode3,didinit; }; struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode); +struct oracleprice_info +{ + CPubKey pk; + std::vector data; + int32_t height; +}; + #ifdef ENABLE_WALLET extern CWallet* pwalletMain; #endif @@ -92,8 +99,21 @@ bool mySendrawtransaction(std::string res); 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_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp); +CScript GetScriptForMultisig(int nRequired, const std::vector& keys); +int64_t CCaddress_balance(char *coinaddr); +CPubKey CCtxidaddr(char *txidaddr,uint256 txid); 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::vectorpublishers); +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 &origpubkey,std::string &name,std::string &description); +uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey); +uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &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 origpubkey); // CCcustom CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv); @@ -106,6 +126,8 @@ CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk); CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2); CC *MakeCCcond1(uint8_t evalcode,CPubKey pk); CC* GetCryptoCondition(CScript const& scriptSig); +void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); +void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); bool IsCCInput(CScript const& scriptSig); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); @@ -114,6 +136,10 @@ char *uint256_str(char *dest,uint256 txid); char *pubkey33_str(char *dest,uint8_t *pubkey33); uint256 Parseuint256(char *hexstr); CPubKey pubkey2pk(std::vector pubkey); +int64_t CCfullsupply(uint256 tokenid); +int64_t CCtoken_balance(char *destaddr,uint256 tokenid); +int64_t CCtoken_balance2(char *destaddr,uint256 tokenid); +bool _GetCCaddress(char *destaddr,uint8_t evalcode,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 ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 4764f4ff6..a9d3f68e7 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -41,7 +41,7 @@ bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScrip std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret) { auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*cond; CPubKey unspendablepk; + CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*othercond3=0,*cond; CPubKey unspendablepk; n = mtx.vout.size(); for (i=0; iunspendableaddr2); privkey = cp->unspendablepriv2; if ( othercond2 == 0 ) - othercond2 = MakeCCcond1(cp->evalcode,cp->unspendablepk2); + othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2); cond = othercond2; } + else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 ) + { + //fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3); + privkey = cp->unspendablepriv3; + if ( othercond3 == 0 ) + othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3); + cond = othercond3; + } else { fprintf(stderr,"vini.%d has unknown CC address.(%s)\n",i,destaddr); @@ -155,6 +163,10 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran cc_free(mycond); if ( othercond != 0 ) cc_free(othercond); + if ( othercond2 != 0 ) + cc_free(othercond2); + if ( othercond3 != 0 ) + cc_free(othercond3); std::string strHex = EncodeHexTx(mtx); if ( strHex.size() > 0 ) return(strHex); @@ -212,6 +224,50 @@ int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout) return(0); } +int64_t CCaddress_balance(char *coinaddr) +{ + int64_t sum = 0; std::vector > unspentOutputs; + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::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 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 origpubkey; + std::vector > unspentOutputs; + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::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 ) + { + char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN); + 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 i,abovei,belowi; int64_t above,below,gap,atx_value; @@ -301,6 +357,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3 up->txid = txid; up->nValue = out.tx->vout[out.i].nValue; up->vout = vout; + //fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos); if ( n >= maxutxos ) break; } @@ -333,12 +390,16 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3 remains -= up->nValue; utxos[ind] = utxos[--n]; memset(&utxos[n],0,sizeof(utxos[n])); + //fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs); if ( totalinputs >= total || (i+1) >= maxinputs ) break; } free(utxos); if ( totalinputs >= total ) + { + //fprintf(stderr,"return totalinputs %.8f\n",(double)totalinputs/COIN); return(totalinputs); + } #endif return(0); } diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index fea8e0ddf..e03564971 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -63,6 +63,7 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2) CTxOut vout; CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2); vout = CTxOut(nValue,CCPubKey(payoutCond)); + fprintf(stderr,"payoutCond: %s\n",cc_conditionToJSONString(payoutCond)); cc_free(payoutCond); return(vout); } @@ -169,6 +170,22 @@ CPubKey pubkey2pk(std::vector pubkey) return(pk); } +void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr) +{ + cp->evalcode2 = evalcode; + cp->unspendablepk2 = pk; + memcpy(cp->unspendablepriv2,priv,32); + strcpy(cp->unspendableaddr2,coinaddr); +} + +void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr) +{ + cp->evalcode3 = evalcode; + cp->unspendablepk3 = pk; + memcpy(cp->unspendablepriv3,priv,32); + strcpy(cp->unspendableaddr3,coinaddr); +} + bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) { CTxDestination address; txnouttype whichType; @@ -181,13 +198,29 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) return(false); } -bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk) +bool pubkey2addr(char *destaddr,uint8_t *pubkey33) +{ + std::vectorpk; int32_t i; + for (i=0; i<33; i++) + pk.push_back(pubkey33[i]); + return(Getscriptaddress(destaddr,CScript() << pk << OP_CHECKSIG)); +} + +CPubKey CCtxidaddr(char *txidaddr,uint256 txid) +{ + uint8_t buf33[33]; CPubKey pk; + buf33[0] = 0x02; + endiancpy(&buf33[1],(uint8_t *)&txid,32); + pk = buf2pk(buf33); + Getscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG); + return(pk); +} + +bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk) { CC *payoutCond; destaddr[0] = 0; - if ( pk.size() == 0 ) - pk = GetUnspendable(cp,0); - if ( (payoutCond= MakeCCcond1(cp->evalcode,pk)) != 0 ) + if ( (payoutCond= MakeCCcond1(evalcode,pk)) != 0 ) { Getscriptaddress(destaddr,CCPubKey(payoutCond)); cc_free(payoutCond); @@ -195,6 +228,14 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk) 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) { CC *payoutCond; @@ -323,6 +364,8 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector param //if ( txid == cp->prevtxid ) // return(true); //fprintf(stderr,"process CC %02x\n",cp->evalcode); + cp->evalcode2 = cp->evalcode3 = 0; + cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0; if ( paramsNull.size() != 0 ) // Don't expect params return eval->Invalid("Cannot have params"); else if ( ctx.vout.size() == 0 ) diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 8adecb3e4..1ddbdc4f8 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -167,7 +167,6 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.n-1: opreturn [EVAL_ASSETS] ['c'] [{"":""}] return eval->Invalid("unexpected AssetValidate for createasset"); break; - case 't': // transfer //vin.0: normal input //vin.1 .. vin.n-1: valid CC outputs @@ -176,7 +175,7 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid] if ( inputs == 0 ) return eval->Invalid("no asset inputs for transfer"); - fprintf(stderr,"transfer validated %.8f -> %.8f\n",(double)inputs/COIN,(double)outputs/COIN); + fprintf(stderr,"transfer validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts); break; case 'b': // buyoffer diff --git a/src/cc/dapps/oracle_dapp.sh b/src/cc/dapps/oracle_dapp.sh deleted file mode 100755 index f6efd6a2b..000000000 --- a/src/cc/dapps/oracle_dapp.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# SET AC -read -p "Enter AC name you use : " acname -sed -i "/#define ACNAME */c\#define ACNAME \"$acname\"" oraclefeed.c -# Set ORACLETXID -read -p "Enter your oracle TXID (Oracle should have L data type) : " oracletxid -sed -i "/#define ORACLETXID */c\#define ORACLETXID \"$oracletxid\"" oraclefeed.c -# SET PUBKEY -read -p "Enter your pubkey : " pubkey -sed -i "/#define MYPUBKEY */c\#define MYPUBKEY \"$pubkey\"" oraclefeed.c -# COMPILATION -echo "Great, compiling !" -gcc oraclefeed.c -lm -o oracle_dapp -mv oracle_dapp ../../oracle_dapp -echo "Oracle is ready to use !" -while true; do - read -p "Would you like to run BTCUSD oracle app? [Y/N]" yn - case $yn in - [Yy]* ) cd ../..; ./oracle_dapp; break;; - [Nn]* ) exit;; - * ) echo "Please answer yes or no.";; - esac -done diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index f32ef3f73..297b92a01 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -19,7 +19,6 @@ #include #include "cJSON.c" - char hexbyte(int32_t c) { c &= 0xf; @@ -309,63 +308,577 @@ uint64_t get_btcusd() return(btcusd); } -cJSON *get_komodocli(char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2) +char *REFCOIN_CLI; + +cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3) { - long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,*fname = "/tmp/komodocli"; - sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,fname); + long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[256]; + sprintf(fname,"/tmp/oraclefeed.%s",method); + if ( acname[0] != 0 ) + { + if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 ) + printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname); + sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,fname); + } + else if ( strcmp(refcoin,"KMD") == 0 ) + sprintf(cmdstr,"./komodo-cli %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,fname); + else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 ) + { + sprintf(cmdstr,"%s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname); + printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr); + } system(cmdstr); *retstrp = 0; if ( (jsonstr= filestr(&fsize,fname)) != 0 ) { //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr); - if ( (retjson= cJSON_Parse(jsonstr)) == 0 ) + if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 ) *retstrp = jsonstr; else free(jsonstr); } return(retjson); } -void bntn() +bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson) { - 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 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) -{ - char *hexstr,*retstr; cJSON *retjson; + char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); if ( (hexstr= jstr(hexjson,"hex")) != 0 ) { - if ( (retjson= get_komodocli(&retstr,acname,"sendrawtransaction",hexstr,"","")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 ) { //fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0)); free_json(retjson); } else if ( retstr != 0 ) { - fprintf(stderr,"txid.(%s)\n",retstr); + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(txid.bytes,32,retstr); + } + fprintf(stderr,"broadcast %s txid.(%s)\n",acname,bits256_str(str,txid)); free(retstr); } } + return(txid); +} + +bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis) +{ + char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); + sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"","")) != 0 ) + { + fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(txid.bytes,32,retstr); + } + fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid)); + free(retstr); + } + return(txid); +} + +int32_t get_coinheight(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr; int32_t height=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 ) + { + height = jint(retjson,"blocks"); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s get_coinheight.(%s) error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(height); +} + +bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height) +{ + cJSON *retjson; char *retstr,heightstr[32]; bits256 hash; + memset(hash.bytes,0,sizeof(hash)); + sprintf(heightstr,"%d",height); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 ) + { + fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(hash.bytes,32,retstr); + } + free(retstr); + } + return(hash); +} + +bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash) +{ + cJSON *retjson; char *retstr,str[65]; bits256 merkleroot; + memset(merkleroot.bytes,0,sizeof(merkleroot)); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 ) + { + merkleroot = jbits256(retjson,"merkleroot"); + //fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s %s get_coinmerkleroot error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(merkleroot); +} + +int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight) +{ + int32_t height = 0; char str[65]; + if ( prevheight == 0 ) + height = get_coinheight(refcoin,acname) - 20; + else height = prevheight + 1; + if ( height > 0 ) + { + *blockhashp = get_coinblockhash(refcoin,acname,height); + if ( bits256_nonz(*blockhashp) != 0 ) + { + *merklerootp = get_coinmerkleroot(refcoin,acname,*blockhashp); + if ( bits256_nonz(*merklerootp) != 0 ) + return(height); + } + } + memset(blockhashp,0,sizeof(*blockhashp)); + memset(merklerootp,0,sizeof(*merklerootp)); + return(0); +} + +cJSON *get_gatewayspending(char *refcoin,char *acname,char *oraclestxidstr) +{ + cJSON *retjson; char *retstr; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",oraclestxidstr,refcoin,"","")) != 0 ) + { + //printf("pending.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s get_gatewayspending.(%s) error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_rawmempool(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 ) + { + //printf("mempool.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_rawmempool.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr) +{ + cJSON *retjson; char *retstr,jsonbuf[256]; + if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 ) + printf("warning: assumes %s has addressindex enabled\n",refcoin); + sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 ) + { + //printf("addressutxos.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_rawtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +void importaddress(char *refcoin,char *acname,char *depositaddr) +{ + cJSON *retjson; char *retstr; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,"","true","")) != 0 ) + { + printf("importaddress.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"importaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } +} + +cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) +{ + cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid; + *totalp = 0; + if ( (n= cJSON_GetArraySize(unspents)) > 0 ) + { + for (i=0; i= required ) + break; + } + } + } + return(vins); +} + +char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signeraddr,char *withdrawaddr,int64_t satoshis) +{ + char *retstr,*retstr2,array[128],*txstr = 0; cJSON *retjson2,*retjson,*vins,*vouts; int64_t txfee,total,change = 0; + if ( strcmp(refcoin,"BTC") == 0 ) + txfee = 20000; + else txfee = 10000; + if ( satoshis < txfee ) + { + printf("createmultisig satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN); + return(0); + } + satoshis -= txfee; + sprintf(array,"[\"%s\"]",depositaddr); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 ) + { + //createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...} + if ( (vins= getinputarray(&total,retjson,satoshis)) != 0 ) + { + if ( total >= satoshis ) + { + vouts = cJSON_CreateObject(); + jaddnum(vouts,withdrawaddr,(double)satoshis/SATOSHIDEN); + if ( total > satoshis+txfee ) + { + change = (total - satoshis); + jaddnum(vouts,depositaddr,(double)change/SATOSHIDEN); + } + char *argA,*argB; + argA = jprint(vins,1); + argB = jprint(vouts,1); + if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 ) + { + printf("createmultisig: unexpected JSON2.(%s)\n",jprint(retjson2,0)); + free_json(retjson2); + } + else if ( txstr == 0 ) + printf("createmultisig: null txstr and JSON2\n"); + free(argA); + free(argB); + } + } + } + else if ( retstr != 0 ) + { + printf("createmultisig: unexpected null JSON, retstr.(%s)\n",retstr); + free(retstr); + } + else printf("createmultisig: null retstr and JSON\n"); + return(txstr); +} + +cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx) +{ + char *retstr,*hexstr; cJSON *retjson; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 ) + { + if ( jint(retjson,"complete") != 0 ) + return(retjson); + else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) ) + { + jaddnum(retjson,"partialtx",1); + return(retjson); + } + free_json(retjson); + } + return(0); +} + +char *get_gatewaysmultisig(char *refcoin,char *acname,char *bindtxidstr,char *withtxidstr,char *txidaddr) +{ + char *retstr,*hexstr,*hex=0; cJSON *retjson; + if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",bindtxidstr,refcoin,withtxidstr,txidaddr)) != 0 ) + { + if ( (hexstr= jstr(retjson,"hex")) != 0 ) + hex = clonestr(hexstr); + free_json(retjson); + } + return(hex); +} + +void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin,bits256 cointxid) +{ + char str[65],str2[65],*retstr; cJSON *retjson; + printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid)); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,bits256_str(str2,cointxid),"")) != 0 ) + { + komodobroadcast(refcoin,acname,retjson); + free_json(retjson); + } + else if ( retstr != 0 ) + { + printf("error parsing gatewaysmarkdone.(%s)\n",retstr); + free(retstr); + } +} + +int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr) +{ + char *oracle,*retstr,*name,*deposit; cJSON *retjson; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 ) + { + if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 ) + { + strcpy(depositaddr,deposit); + if ( jstr(retjson,"coin") != 0 && strcmp(jstr(retjson,"coin"),coin) == 0 && jint(retjson,"N") >= 1 ) + { + *Mp = jint(retjson,"M"); + *Np = jint(retjson,"N"); + //printf("(%s)\n",jprint(retjson,0)); + } else printf("coin.%s vs %s\n",jstr(retjson,"coin"),coin); + } else printf("%s != %s\n",oracle,oraclestr); + free_json(retjson); + } + else if ( retstr != 0 ) + { + printf("error parsing get_gatewaysinfo.(%s)\n",retstr); + free(retstr); + } + if ( *Mp <= 0 || *Np <= 0 ) + return(-1); + else return(0); +} + +int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr) +{ + cJSON *txobj,*vouts,*vout,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numvouts,retval = 0; + if ( (txobj= get_rawtransaction(refcoin,acname,txid)) != 0 ) + { + if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 ) + { + for (i=0; i 0 ) + { + num = 1; + break; + } + } + } + free_json(array); + } else return(-1); + } + return(num); +} + +void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N) +{ + // check queue to prevent duplicate + // check KMD chain and mempool for txidaddr + // if txidaddr exists properly, spend the marker (txid.2) + // create withdraw tx and sign it + /// if enough sigs, sendrawtransaction and when it confirms spend marker (txid.2) + /// if not enough sigs, post partially signed to acname with marker2 + // monitor marker2, for the partially signed withdraws + cJSON *retjson,*pending,*item,*clijson; char str[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,retval,processed = 0; bits256 txid,cointxid,origtxid,zeroid; int64_t satoshis; + memset(&zeroid,0,sizeof(zeroid)); + if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 ) + { + if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 ) + { + if ( (pending= jarray(&n,retjson,"pending")) != 0 ) + { + for (i=0; i","amount":0.0001},{"address":"","amount":}]' + txid = sendtoaddress("KMD",acname,txidaddr,10000); + if ( bits256_nonz(txid) != 0 && coinaddrexists("KMD",acname,txidaddr) > 0 ) + { + // the actual withdraw + if ( strcmp(depositaddr,signeraddr) == 0 ) + { + cointxid = sendtoaddress(refcoin,"",withdrawaddr,satoshis); + if ( bits256_nonz(cointxid) != 0 ) + { + fprintf(stderr,"withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); + gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); + processed++; + } + else + { + fprintf(stderr,"ERROR withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); + } + } + else + { + if ( (rawtx= get_gatewaysmultisig(refcoin,acname,bindtxidstr,bits256_str(str,origtxid),txidaddr)) == 0 ) + { + rawtx = createmultisig(refcoin,"",depositaddr,signeraddr,withdrawaddr,satoshis); + } + if ( rawtx != 0 ) + { + if ( (clijson= addmultisignature(refcoin,"",signeraddr,rawtx)) != 0 ) + { + if ( jint(clijson,"complete") != 0 ) + { + cointxid = komodobroadcast(refcoin,"",clijson); + if ( bits256_nonz(cointxid) != 0 ) + { + fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); + gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); + } + } + else if ( jint(clijson,"partialtx") != 0 ) + { + // 10000 + ith -> txidaddr + txid = komodobroadcast("KMD",acname,clijson); + fprintf(stderr,"%s M.%d of N.%d partialtx %s sent\n",refcoin,M,N,bits256_str(str,txid)); + } + free_json(clijson); + } + processed++; + free(rawtx); + } else fprintf(stderr,"couldnt create msig rawtx\n"); + } + } + } + else if ( retval > 0 ) + { + fprintf(stderr,"already did withdraw %s %s %.8f processed\n",refcoin,withdrawaddr,(double)satoshis/SATOSHIDEN); + gatewaysmarkdone("KMD",acname,origtxid,refcoin,zeroid); + } + } + } + } + } + free_json(retjson); + } +} + +int32_t get_oracledata(char *refcoin,char *acname,int32_t prevheight,char *hexstr,int32_t maxsize,char *format) +{ + int32_t i; uint32_t height; uint64_t price; bits256 blockhash,merkleroot; + hexstr[0] = 0; + if ( format[0] == 'L' || format[0] == 'l' ) + { + if ( (price= get_btcusd()) != 0 ) + { + for (i=0; i<8; i++) + sprintf(&hexstr[i*2],"%02x",(uint8_t)((price >> (i*8)) & 0xff)); + hexstr[16] = 0; + return(16); + } + } + else if ( strcmp(format,"Ihh") == 0 ) + { + if ( (height= get_coinheader(refcoin,acname,&blockhash,&merkleroot,prevheight)) > prevheight ) + { + for (i=0; i<4; i++) + sprintf(&hexstr[i*2],"%02x",(uint8_t)((height >> (i*8)) & 0xff)); + for (i=31; i>=0; i--) + sprintf(&hexstr[8 + (31-i)*2],"%02x",blockhash.bytes[i]); + for (i=31; i>=0; i--) + sprintf(&hexstr[8 + 64 + (31-i)*2],"%02x",merkleroot.bytes[i]); + hexstr[8 + 64*2] = 0; + return(height); + } + } + return(0); } /* @@ -390,39 +903,81 @@ oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 034 */ -#define ORACLETXID "4895f631316a649e216153aee7a574bd281686265dc4e8d37597f72353facac3" -#define MYPUBKEY "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92" -#define ACNAME "ORCL" +// ./a.out AT5 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 Ihh e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e int32_t main(int32_t argc,char **argv) { - cJSON *clijson,*clijson2,*regjson,*item; int32_t i,j,n; char *retstr,*retstr2,*pkstr,hexstr[64]; uint64_t price; + cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,M,N,n,height,prevheight = 0; char *format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid; + if ( argc < 6 ) + { + printf("usage: oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID [refcoin_cli]\n"); + return(-1); + } printf("Powered by CoinDesk (%s) %.8f\n","https://www.coindesk.com/price/",dstr(get_btcusd())); + acname = argv[1]; + oraclestr = argv[2]; + pkstr = argv[3]; + format = argv[4]; + bindtxidstr = argv[5]; + if ( argc > 6 ) + REFCOIN_CLI = argv[6]; + else REFCOIN_CLI = "./komodo-cli"; + if ( strncmp(format,"Ihh",3) != 0 && format[0] != 'L' ) + { + printf("only formats of L and Ihh are supported now\n"); + return(-1); + } + M = N = 1; + acheight = 0; + refcoin[0] = 0; while ( 1 ) { retstr = 0; - if ( (price= get_btcusd()) != 0 && (clijson= get_komodocli(&retstr,ACNAME,"oraclesinfo",ORACLETXID,"","")) != 0 ) + if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_komodocli("KMD",&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 ) { + if ( refcoin[0] == 0 && jstr(clijson,"name") != 0 ) + { + strcpy(refcoin,jstr(clijson,"name")); + if ( strcmp("KMD",refcoin) != 0 && argc != 7 ) + { + printf("need to specify path to refcoin's cli as last argv\n"); + exit(0); + } + if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr) < 0 ) + { + printf("cant find bindtxid.(%s)\n",bindtxidstr); + exit(0); + } + importaddress(refcoin,"",depositaddr); + printf("set refcoin %s <- %s [%s] M.%d of N.%d\n",depositaddr,refcoin,REFCOIN_CLI,M,N); + } if ( (regjson= jarray(&n,clijson,"registered")) != 0 ) { for (i=0; i> (j*8)) & 0xff)); - hexstr[16] = 0; - if ( (clijson2= get_komodocli(&retstr2,ACNAME,"oraclesdata",ORACLETXID,hexstr,"")) != 0 ) + if ( (height= get_oracledata(refcoin,"",prevheight,hexstr,sizeof(hexstr),"Ihh")) != 0 ) { - //printf("data.(%s)\n",jprint(clijson2,0)); - komodobroadcast(ACNAME,clijson2); - free_json(clijson2); - } - else if ( retstr2 != 0 ) - { - printf("error parsing oraclesdata.(%s)\n",retstr2); - free(retstr2); + if ( (clijson2= get_komodocli("KMD",&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 ) + { + //printf("data.(%s)\n",jprint(clijson2,0)); + txid = komodobroadcast("KMD",acname,clijson2); + if ( bits256_nonz(txid) != 0 ) + { + prevheight = height; + acheight = get_coinheight(refcoin,""); + printf("%s ht.%d <- %s\n",refcoin,height,hexstr); + update_gatewayspending(refcoin,acname,bindtxidstr,M,N); + } + free_json(clijson2); + } + else if ( retstr2 != 0 ) + { + printf("error parsing oraclesdata.(%s)\n",retstr2); + free(retstr2); + } } break; } @@ -435,7 +990,8 @@ int32_t main(int32_t argc,char **argv) printf("got json parse error.(%s)\n",retstr); free(retstr); } - sleep(60); + sleep(10); + // best check is for txid to not be in mempool, ie confirmed } return(0); } diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index 8f5d00f26..a0b3a7210 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -15,16 +15,192 @@ #include "CCGateways.h" +/* + prevent duplicate bindtxid via mempool scan + wait for notarization for oraclefeed and validation of gatewaysdeposit + debug multisig and do partial signing + validation + + string oracles + */ + /* Uses MofN CC's normal msig handling to create automated deposits -> token issuing. And partial signing by the selected pubkeys for releasing the funds. A user would be able to select which pubkeys to use to construct the automated deposit/redeem multisigs. 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 + + In order to create a new gateway it is necessary to follow some strict steps. + 1. create a token with the max possible supply that will be issued + 2. transfer 100% of them to the gateways CC's global pubkey's asset CC address. (yes it is a bit confusing) + 3. create an oracle with the identical name, ie. KMD and format must start with Ihh (height, blockhash, merkleroot) + 4. register a publisher and fund it with a subscribe. there will be a special client app that will automatically publish the merkleroots. + 5. Now a gatewaysbind can bind an external coin to an asset, along with the oracle for the merkleroots. the txid from the bind is used in most of the other gateways CC calls + + usage: + ./c tokencreate KMD 1000000 KMD_equivalent_token_for_gatewaysCC + a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a + + transfer to gateways pubkey: 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 RDMqGyREkP1Gwub1Nr5Ye8a325LGZsWBCb + ./c tokentransfer a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40 100000000000000 + 2206fc39c0f384ca79819eb491ddbf889642cbfe4d0796bb6a8010ed53064a56 + + ./c oraclescreate KMD blockheaders Ihh + 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 + + ./c oraclesregister 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 1000000 + 83b59eac238cbe54616ee13b2fdde85a48ec869295eb04051671a1727c9eb402 + + ./c oraclessubscribe 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 1000 + f9499d8bb04ffb511fcec4838d72e642ec832558824a2ce5aed87f1f686f8102 + + gatewaysbind tokenid oracletxid coin tokensupply M N pubkey(s) + ./c gatewaysbind a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 KMD 100000000000000 1 1 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 + e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e + + ./c gatewaysinfo e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e + { + "result": "success", + "name": "Gateways", + "pubkey": "02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92", + "coin": "KMD", + "oracletxid": "1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808", + "taddr": 0, + "prefix": 60, + "prefix2": 85, + "deposit": "", + "tokenid": "a7398a8748354dd0a3f8d07d70e65294928ecc3674674bb2d9483011ccaa9a7a", + "totalsupply": "1000000.00000000", + "remaining": "1000000.00000000", + "issued": "0.00000000" + } + + To make a gateway deposit, send the funds to the "deposit" address, along with any amount to the same pubkey address you want to get the assetized KMD to appear in. + + 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 pubkey for RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha + ./komodo-cli z_sendmany "" '[{"address":"RFpxgqff7FDHFuHa3jSX5NzqqWCcELz8ha","amount":0.0001},{"address":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","amount":7.6999}]' + bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 height.1003776 merkle.90aedc2f19200afc9aca2e351438d011ebae8264a58469bf225883045f61917f + + ./komodo-cli gettxoutproof '["bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009"]' + 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b + + ./komodo-cli getrawtransaction bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 + 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b + + gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount + ./komodo-cli -ac_name=AT5 gatewaysdeposit e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e 1003776 KMD bc41a00e429db741c3199f17546a48012fd3b7eea45dfc6bc2f5228278133009 0 010000000149964cdcd17fe9b1cae4d0f3b5f5db301d9b4f54099fdf4d34498df281757094010000006a4730440220594f3a630dd73c123f44621aa8bb9968ab86734833453dd479af6d79ae6f584202207bb5e35f13b337ccc8a88d9a006c8c5ddb016c0a6f4f2dc44357a8128623d85d01210223154bf53cd3a75e64d86697070d6437c8f0010a09c1df35b659e31ce3d79b5dffffffff0310270000000000001976a91447d2e323a14b0c3be08698aa46a9b91489b189d688ac701de52d000000001976a91459fdba29ea85c65ad90f6d38f7a6646476b26b1688acb0a86a00000000001976a914f9a9daf5519dae38b8b61d945f075da895df441d88ace18d965b 04000000232524ea04b54489eb222f8b3f566ed35504e3050488a63f0ab7b1c2030000007f91615f04835822bf6984a56482aeeb11d03814352eca9afc0a20192fdcae900000000000000000000000000000000000000000000000000000000000000000268e965ba608071d0800038e16762900000000000000000000000000000000000000000042008dd6fd4005016b4292b05df6dfd316c458c53e28fb2befb96e4870a40c6c04e733d75d8a7a18cce34fe326005efdc403bfa4644e30eeafdaeff34419edc591299e6cc5933cb2eeecbab5c4dfe97cd413b75215999a3dd02b540373581e81d8512bff1640590a6b4da4aaa9b8adc0102c38ca0022daed997b53ed192ba326e212fba5e505ce29e3ad149cef7f48d0e00948a1acd81731d84008760759211eb4abbc7b037939a7964182edb59cf9065357e864188ee5fc7316e8796963036bb99eeb9f06c95d64f78749ecec7181c12eb5d83a3b9b1c1e8a0aae9a20ce04a250b28216620bfc99bb81a6de4db80b93a5aea916de97c1a272e26644abdd683f19c5e3174a2e4513ed767d8f11a4c3074295f697839c5d9139676a813451cc7da38f68cbae5d990a79075f98903233ca04fe1b4b099e433585e5adcc45d41d54a9c648179297359c75950a5e574f13f70b728bbbf552770256315cd0a00139d6ab6934cb5ed70a4fc01a92611b096dd0028f17f4cc687b75f37dca530aa47a18321c50528dbd9272eabb3e13a87021a05918a6d2627e2caba6d7cf1a9f0b831ea3337b9a6af92746d83140078d60c72b6beacf91c9e68a34cee209e08670be1d17ff8d80b7a2285b1325461a2e33f2ee675593f1900e066a5d212615cd8da18749b0e684eee73edcc9031709be715b889c6d015cf4bd4ad5ab7e21bd3492c208930a54d353ef36a437f507ead38855633c1b88d060d9e4221ca8ce2f698e8a6ae0d41e9ace3cbd401f1e0f07650e9c126d4ef20278c8be6e85c7637513643f8d02d7ad64c09da11c16429d60e5160c345844b8158ece62794e8ad280d4e4664150e74978609ece431e51a9f9e1ce8aa49c16f36c7fd12b71acc42d893e18476b8b1e144a8175519612efc93e0aecc61f3b21212c958b0e2331d76aaa62faf11a58fe2bd91ab9ab01b906406c9bbc02df2a106e67182aae0a20b538bf19f09c57f9de5e198ba254580fb1b11e22ad526550093420cb7c68628d4c3ad329c8acc6e219093d277810ed016b6099b7e3781de412a22dacedaa2acf29e8062debcd85c7b9529a20b2782a2470763ac27cf89611a527d43ac89b8063ffb93b6ed993425194f8ee821a8493a563072c896f9584f95db28e3f2fc5fb4a6f3c39d615cd563641717cd50afb73ed3989cbf504b2043882993ce9575f56402534173b1396fbc13df80920b46788ae340ad5a91f25177cc74aa69024d76f56166199d2e4d50a053555256c4e3137ea1cee1130e916a88b6ee5cf2c85652fb8824d5dacfa485e3ef6190591ac0c2fcacc4fc7deb65aca4b0b89b76e35a46b0627e2e967cc63a5d606a984c8e63eabb98fde3e69114340ae524c974cb936e57690e98a7a74533f6f7d1d0496976496b54d14a8163efb32b70dfbb79d80a3022c4f53571c08bf044270565716b435084376714b224ab23e9817c05af8223723afc0577af5c8fc28f71036ca82528aaa4ca9bcd18a50e25d2a528f183d3a2074d968d170876d8dce434c5937261b55173ab87e03d5632ca0834fdc5387c15ab3a17d75c0f274004f289ff1bf7d14e97fdf4172eb49adfb418cc2f4794806ae7c0111c97df4d65d38679ec93fea3ef738ed565e8906a8fe1861cafe3938c772fedcfab40159938e06ef414fd299f2355c6d3369bc1bd3c4db64ce205f0a1b70a40030f505b736e28230de82e97776b5ee7b10708bb3020d28cec7a8e124549ec80c547ac4e7b52bf397c72bcfce30820554ab8fb4d1f73b209bc32a0e7e878843cdbf5f01222728ccea7e6ab7cb5e3fee3234f5b85d1985f91492f6ceaa6454a658dab5074f163ce26ed753137fa61c940679de13bd7b212cd3cf2b334f5201cecbc7473342bd7a239e09169bccd56d03000000037a9068df0625e548e71263c8361b4e904c998378f6b9e32729c3f19b10ad752e093013788222f5c26bfc5da4eeb7d32f01486a54179f19c341b79d420ea041bc8878d22fad4692b2d609c3cf190903874d3682a714c7483518c9392e07c25035010b 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999 + -> 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 + + to get the merkleroots onchain, from the multisig signers nodes run the oraclefeed program with acname oracletxid pubkey Ihh + ./oraclefeed AT5 1f1aefcca2bdea8196cfd77337fb21de22d200ddea977c2f9e8742c55829d808 02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 Ihh + + gatewaysclaim bindtxid coin deposittxid destpub amount + ./c gatewaysclaim e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 9d80ea79a65aaa0d464f8b762356fa01047e16e9793505a22ca04559f81a6eb6 0223d114dededb04f253816d6ad0ce78dd08c617c94ce3c53bf50dc74a5157bef8 7.6999 + + now the asset is in the pubkey's asset address! + it can be used, traded freely and any node who has the asset can do a gatewayswithdraw + + gatewayswithdraw bindtxid coin withdrawpub amount + ./c gatewayswithdraw e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD 03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828 1 + ef3cc452da006eb2edda6b6ed3d3347664be51260f3e91f59ec44ec9701367f0 + + Now there is a withdraw pending, so it needs to be processed by the signing nodes on the KMD side + + gatewayspending bindtxid coin + gatewayspending will display all pending withdraws and if it is done on one of the msigpubkeys, then it will queue it for processing + ./c gatewayspending e6c99f79d4afb216aa8063658b4222edb773dd24bb0f8e91bd4ef341f3e47e5e KMD + + + Implementation Issues: + When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly. + + Care must be taken so that tokens are not lost and can be converted back. + + This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241 + + The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS. + + */ + + +int32_t GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue) +{ + char destaddr[64],str[65]; + Getscriptaddress(destaddr,scriptPubKey); + fprintf(stderr,"GatewaysAddQueue: %s %s %s %.8f\n",coin.c_str(),uint256_str(str,txid),destaddr,(double)nValue/COIN); +} // 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 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 << oracletxid); + return(opret); +} + +CScript EncodeGatewaysOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector publishers,std::vectortxids,int32_t height,uint256 cointxid,std::string deposithex,std::vectorproof,CPubKey destpub,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 << destpub << amount); + return(opret); +} + +uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &cointxid,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) +{ + std::vector 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 >> destpub; 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 &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2) +{ + std::vector 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; ss >> oracletxid) != 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 prefix.%d\n",prefix); + } + return(f); + } else fprintf(stderr,"error decoding bind opret\n"); + return(0); +} + int64_t IsGatewaysvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) { char destaddr[64]; @@ -74,11 +250,12 @@ bool GatewaysExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti else return(true); } -bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; - return(false); std::vector > txids; + fprintf(stderr,"return true without gateways validation\n"); + return(true); numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; @@ -115,101 +292,607 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & // helper functions for rpc calls in rpcwallet.cpp -int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) +int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 refassetid,int64_t total,int32_t maxinputs) { - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; + char coinaddr[64],destaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); + fprintf(stderr,"check %s for gateway inputs\n",coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; - // no need to prevent dup + for (j=0; j 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 ) + Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey); + //fprintf(stderr,"%s vout.%d %.8f %.8f\n",destaddr,vout,(double)vintx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN); + if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) + continue; + GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret); + if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> assetid) != 0 ) { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; + assetid = revuint256(assetid); + //char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for refassetid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,refassetid),uint256_str(str2,assetid),(double)vintx.vout[vout].nValue/COIN); + if ( assetid == refassetid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) + { + //fprintf(stderr,"total %llu maxinputs.%d %.8f\n",(long long)total,maxinputs,(double)it->second.satoshis/COIN); + if ( total != 0 && maxinputs != 0 ) + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + //nValue = it->second.satoshis; + totalinputs += nValue; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) + break; + } } } } return(totalinputs); } -std::string GatewaysGet(uint64_t txfee,int64_t nValue) +int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) // dont forget to check mempool! { - 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; - 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 ) + char markeraddr[64],depositaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; CTransaction tx; + std::vector > addressIndex; + _GetCCaddress(markeraddr,EVAL_GATEWAYS,gatewayspk); + fprintf(stderr,"bind markeraddr.(%s) need to scan mempool also\n",markeraddr); + SetCCtxids(addressIndex,markeraddr); + for (std::vector >::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_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++) + if ( GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - 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 ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' ) { - 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 ) + if ( tokenid == reftokenid ) { - fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL)); - return(rawhex); + fprintf(stderr,"trying to bind an existing tokenid\n"); + return(1); } - //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(""); + return(0); } -UniValue GatewaysInfo() +static int32_t myIs_coinaddr_inmempoolvout(char *coinaddr) { - UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int64_t funding; + int32_t i,n; char destaddr[64]; + BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) + { + const CTransaction &tx = e.GetTx(); + if ( (n= tx.vout.size()) > 0 ) + { + const uint256 &txid = tx.GetHash(); + for (i=0; i > addressIndex; + CCtxidaddr(txidaddr,cointxid); + SetCCtxids(addressIndex,txidaddr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + return(-1); + } + return(myIs_coinaddr_inmempoolvout(txidaddr)); +} + +UniValue GatewaysInfo(uint256 bindtxid) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CMutableTransaction mtx; CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining; result.push_back(Pair("result","success")); result.push_back(Pair("name","Gateways")); cp = CCinit(&C,EVAL_GATEWAYS); Gatewayspk = GetUnspendable(cp,0); - funding = AddGatewaysInputs(cp,mtx,Gatewayspk,0,0); - sprintf(numstr,"%.8f",(double)funding/COIN); - result.push_back(Pair("funding",numstr)); + _GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) + { + depositaddr[0] = 0; + 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 ) + { + if ( N > 1 ) + { + result.push_back(Pair("M",M)); + result.push_back(Pair("N",N)); + for (i=0; i > 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 pubkeys; + cp = CCinit(&C,EVAL_GATEWAYS); + SetCCtxids(addressIndex,cp->unspendableCCaddr); + for (std::vector >::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 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 ( strcmp((char *)"KMD",coin.c_str()) == 0 ) + { + taddr = 0; + prefix = 60; + prefix2 = 85; + } + else + { + fprintf(stderr,"set taddr, prefix, prefix2 for %s\n",coin.c_str()); + taddr = 0; + prefix = 60; + prefix2 = 85; + } + if ( N == 0 || N > 15 || M > N ) + { + fprintf(stderr,"illegal M.%d or N.%d\n",M,N); + return(""); + } + if ( pubkeys.size() != N ) + { + fprintf(stderr,"M.%d N.%d but pubkeys[%d]\n",M,N,(int32_t)pubkeys.size()); + return(""); + } + for (i=0; iunspendableCCaddr,(double)totalsupply/COIN,(double)fullsupply/COIN); + return(""); + } + if ( CCtoken_balance(destaddr,tokenid) != totalsupply ) + { + fprintf(stderr,"Gateway bind.%s (%s) destaddr.%s globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),destaddr,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(""); + } + if ( GatewaysBindExists(cp,gatewayspk,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,bhash,hashBlock,oracletxid; int32_t len,len2,numvouts; int64_t val,merkleht; CPubKey pk; std::vectordata; + txid = zeroid; + char str[65]; + //fprintf(stderr,"start reverse scan %s\n",uint256_str(str,batontxid)); + while ( GetTransaction(batontxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) + { + //fprintf(stderr,"check %s\n",uint256_str(str,batontxid)); + if ( DecodeOraclesData(tx.vout[numvouts-1].scriptPubKey,oracletxid,bhash,pk,data) == 'D' && oracletxid == reforacletxid ) + { + //fprintf(stderr,"decoded %s\n",uint256_str(str,batontxid)); + if ( oracle_format(&hash,&merkleht,0,'I',(uint8_t *)data.data(),0,(int32_t)data.size()) == sizeof(int32_t) && merkleht == height ) + { + len = oracle_format(&hash,&val,0,'h',(uint8_t *)data.data(),sizeof(int32_t),(int32_t)data.size()); + len2 = oracle_format(&mhash,&val,0,'h',(uint8_t *)data.data(),(int32_t)(sizeof(int32_t)+sizeof(uint256)),(int32_t)data.size()); + char str2[65]; fprintf(stderr,"found merkleht.%d len.%d len2.%d %s %s\n",(int32_t)merkleht,len,len2,uint256_str(str,hash),uint256_str(str2,mhash)); + if ( len == sizeof(hash)+sizeof(int32_t) && len2 == 2*sizeof(mhash)+sizeof(int32_t) && mhash != zeroid ) + { + txid = batontxid; + //fprintf(stderr,"set txid\n"); + return(mhash); + } + else + { + //fprintf(stderr,"missing hash\n"); + return(zeroid); + } + } //else fprintf(stderr,"height.%d vs search ht.%d\n",(int32_t)merkleht,(int32_t)height); + batontxid = bhash; + //fprintf(stderr,"new hash %s\n",uint256_str(str,batontxid)); + } else break; + } + fprintf(stderr,"end of loop\n"); + return(zeroid); +} + +/* Get the block merkle root for a proof + * IN: proofData + * OUT: merkle root + * OUT: transaction IDS + */ +uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids) +{ + CMerkleBlock merkleBlock; + if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) + return uint256(); + return merkleBlock.txn.ExtractMatches(txids); +} + +int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub) +{ + std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,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); + } + proofroot = BitcoinGetProofMerkleRoot(proof,txids); + if ( proofroot != merkleroot ) + { + fprintf(stderr,"GatewaysVerify mismatched merkleroot %s != %s\n",uint256_str(str,proofroot),uint256_str(str2,merkleroot)); + return(0); + } + if ( DecodeHexTx(tx,deposithex) != 0 ) + { + Getscriptaddress(claimaddr,tx.vout[claimvout].scriptPubKey); + Getscriptaddress(destpubaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); + if ( strcmp(claimaddr,destpubaddr) == 0 ) + { + for (i=0; i publishers; std::vectortxids; uint256 bindtxid,cointxid; std::vector proof; CPubKey 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' && claimpubkey == mypk ) + { + // coin, bindtxid, publishers + fprintf(stderr,"need to validate deposittxid more\n"); + return(amount); + } + } + return(0); +} + +std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,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 pubkeys,publishers; std::vectortxids; char str[67],depositaddr[64],txidaddr[64]; + cp = CCinit(&C,EVAL_GATEWAYS); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + gatewayspk = GetUnspendable(cp,0); + //fprintf(stderr,"GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size()); + 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,pubkeys,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 0 ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,deposithex,proof,destpub,amount))); + } + fprintf(stderr,"cant find enough inputs\n"); + return(""); +} + +std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount) +{ + CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector msigpubkeys; int64_t totalsupply,depositamount,inputs,CCchange=0; int32_t numvouts; uint256 hashBlock,assetid,oracletxid; char str[65],depositaddr[64],coinaddr[64]; + cp = CCinit(&C,EVAL_GATEWAYS); + 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 deposittxid %s\n",uint256_str(str,bindtxid)); + return(""); + } + if ( (depositamount= GatewaysDepositval(tx,mypk)) != amount ) + { + fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN); + return(""); + } + //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2); + if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + { + if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,assetid,amount,60)) > 0 ) + { + if ( inputs > amount ) + CCchange = (inputs - amount); + mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk)); // transfer back to normal token + if ( CCchange != 0 ) + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,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 withdrawpub,int64_t amount) +{ + CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; 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 msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; + cp = CCinit(&C,EVAL_GATEWAYS); + 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,3*txfee,3) > 0 ) + { + if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,assetid,amount,60)) > 0 ) + { + if ( inputs > amount ) + CCchange = (inputs - amount); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,amount,gatewayspk)); + mtx.vout.push_back(CTxOut(txfee,CScript() << withdrawpub << OP_CHECKSIG)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG)); + if ( CCchange != 0 ) + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk)); + 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 GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid) +{ + CMutableTransaction mtx; CScript opret; CPubKey mypk; struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_GATEWAYS); + if ( txfee == 0 ) + txfee = 5000; + mypk = pubkey2pk(Mypubkey()); + mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript())); + mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'M' << cointxid << refcoin); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); +} + +UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) +{ + UniValue result(UniValue::VOBJ),pending(UniValue::VARR),obj(UniValue::VOBJ); CTransaction tx; std::string coin; CPubKey mypk,gatewayspk; std::vector msigpubkeys; uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],signeraddr[64]; int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + cp = CCinit(&C,EVAL_GATEWAYS); + mypk = pubkey2pk(Mypubkey()); + gatewayspk = GetUnspendable(cp,0); + _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); + return(result); + } + 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(result); + } + n = msigpubkeys.size(); + queueflag = 0; + for (i=0; i >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + if ( GetTransaction(txid,tx,hashBlock,false) != 0 ) + { + Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); + Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); + if ( strcmp(destaddr,coinaddr) == 0 ) + { + obj.push_back(Pair("txid",uint256_str(str,txid))); + CCtxidaddr(txidaddr,txid); + obj.push_back(Pair("txidaddr",txidaddr)); + obj.push_back(Pair("withdrawaddr",withaddr)); + sprintf(numstr,"%.8f",(double)tx.vout[0].nValue/COIN); + obj.push_back(Pair("amount",numstr)); + if ( queueflag != 0 ) + { + obj.push_back(Pair("depositaddr",depositaddr)); + Getscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG); + obj.push_back(Pair("signeraddr",signeraddr)); + } + pending.push_back(obj); + } + } + } + result.push_back(Pair("coin",refcoin)); + result.push_back(Pair("pending",pending)); + result.push_back(Pair("queueflag",queueflag)); + return(result); +} + +std::string GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr) +{ + UniValue result(UniValue::VOBJ); std::string coin,hex; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CPubKey Gatewayspk,mypk; struct CCcontract_info *cp,C; int32_t i,n,complete,partialtx; int64_t totalsupply; + cp = CCinit(&C,EVAL_GATEWAYS); + if ( txfee == 0 ) + txfee = 10000; + complete = partialtx = 0; + mypk = pubkey2pk(Mypubkey()); + Gatewayspk = GetUnspendable(cp,0); + _GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) + { + depositaddr[0] = 0; + 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 > 1 && coin == refcoin ) + { + // need a decentralized way to add signatures to msig tx + n = pubkeys.size(); + for (i=0; ievalcode2 = EVAL_ORACLES; for (i=0; i<32; i++) cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]); while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 ) @@ -222,22 +224,33 @@ int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publ int64_t OracleDatafee(CScript &scriptPubKey,uint256 oracletxid,CPubKey publisher) { - CTransaction oracletx; char markeraddr[64]; CPubKey markerpubkey; uint8_t buf33[33]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0; + CTransaction oracletx; char markeraddr[64]; uint256 hashBlock; std::string name,description,format; int32_t numvouts; int64_t datafee = 0; if ( myGetTransaction(oracletxid,oracletx,hashBlock) != 0 && (numvouts= oracletx.vout.size()) > 0 ) { if ( DecodeOraclesCreateOpRet(oracletx.vout[numvouts-1].scriptPubKey,name,description,format) == 'C' ) { - buf33[0] = 0x02; - endiancpy(&buf33[1],(uint8_t *)&oracletxid,32); - markerpubkey = buf2pk(buf33); - scriptPubKey = CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG; - Getscriptaddress(markeraddr,scriptPubKey); + CCtxidaddr(markeraddr,oracletxid); datafee = OracleCurrentDatafee(oracletxid,markeraddr,publisher); } } return(datafee); } +static uint256 myIs_baton_spentinmempool(uint256 batontxid,int32_t batonvout) +{ + BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) + { + const CTransaction &tx = e.GetTx(); + if ( tx.vout.size() > 0 && tx.vin.size() > 1 && batontxid == tx.vin[1].prevout.hash && batonvout == tx.vin[1].prevout.n ) + { + const uint256 &txid = tx.GetHash(); + //char str[65]; fprintf(stderr,"found baton spent in mempool %s\n",uint256_str(str,txid)); + return(txid); + } + } + return(batontxid); +} + uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 reforacletxid,char *batonaddr,CPubKey publisher,std::vector &dataarg) { uint256 txid,oracletxid,hashBlock,btxid,batontxid = zeroid; int64_t dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk; uint8_t *ptr; std::vector vopret,data; @@ -276,6 +289,35 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora } } } + while ( myIsutxo_spentinmempool(batontxid,1) != 0 ) + batontxid = myIs_baton_spentinmempool(batontxid,1); + return(batontxid); +} + +uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk) +{ + std::vector > unspentOutputs; + CTransaction regtx; uint256 hash,txid,batontxid,oracletxid; CPubKey pk; int32_t numvouts,height,maxheight=0; int64_t datafee; char markeraddr[64],batonaddr[64]; std::vector data; struct CCcontract_info *cp,C; + batontxid = zeroid; + cp = CCinit(&C,EVAL_ORACLES); + CCtxidaddr(markeraddr,reforacletxid); + SetCCunspents(unspentOutputs,markeraddr); + //char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk)); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + //fprintf(stderr,"check %s\n",uint256_str(str,txid)); + height = (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 && pk == refpk ) + { + Getscriptaddress(batonaddr,regtx.vout[1].scriptPubKey); + batontxid = OracleBatonUtxo(10000,cp,oracletxid,batonaddr,pk,data); + break; + } + } + } return(batontxid); } @@ -389,7 +431,6 @@ int64_t correlate_price(int32_t height,int64_t *prices,int32_t n) int32_t i,j; int64_t price = 0; if ( n == 1 ) return(prices[0]); - // deterministic sort, like heapsort for (i=0; i %llu ht.%d\n",(long long)price,height); } -int64_t OracleCorrelatedPrice(int32_t height,char *format,std::vector datas[ORACLES_MAXPROVIDERS],int32_t n) +int64_t OracleCorrelatedPrice(int32_t height,std::vector origprices) { - int64_t prices[ORACLES_MAXPROVIDERS]; int32_t i,m=0; uint256 hash; int64_t val,price=0; - if ( format[0] == 'L' ) + std::vector sorted; int32_t i,n; int64_t *prices,price; + 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::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 &publishers,CPubKey pk,int32_t height,std::vector data,int32_t maxheight) +{ + struct oracleprice_info item; int32_t flag = 0; + for (std::vector::iterator it=publishers.begin(); it!=publishers.end(); it++) { - for (i=0; ipk ) { - oracle_format(&hash,&val,0,'L',(uint8_t *)datas[i].data(),0,(int32_t)datas[i].size()); - if ( val != 0 ) - prices[m++] = val; + flag = 1; + if ( height > it->height ) + { + it->height = height; + it->data = data; + return(height); + } } } - if ( m != 0 ) - price = correlate_price(height,prices,m); - return(0); + if ( flag == 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) { std::vector > 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 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 data; struct CCcontract_info *cp,C; std::vector publishers; std::vector prices; + if ( format[0] != 'L' ) + return(0); cp = CCinit(&C,EVAL_ORACLES); SetCCunspents(unspentOutputs,markeraddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { 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 ) { - for (j=0; j maxheight ) + maxheight = ht; } } } - return(OracleCorrelatedPrice(height,format,datas,n)); + if ( maxheight > 10 ) + { + for (std::vector::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); } int64_t IsOraclesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) { - char destaddr[64]; + //char destaddr[64]; if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 )// && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) + //if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) return(tx.vout[v].nValue); } return(0); @@ -485,8 +555,8 @@ bool OraclesDataValidate(struct CCcontract_info *cp,Eval* eval,const CTransactio else { //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant Oracles from mempool"); + //if ( hashBlock == zerohash ) + // return eval->Invalid("cant Oracles from mempool"); if ( (assetoshis= IsOraclesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) { if ( i == 1 && vinTx.vout[1].scriptPubKey != tx.vout[1].scriptPubKey ) @@ -600,6 +670,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub { txid = it->first.txhash; vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"oracle check %s/v%d\n",uint256_str(str,txid),vout); if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { // get valid CC payments @@ -612,8 +683,8 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub n++; if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) break; - } - } + } //else fprintf(stderr,"nValue %.8f or utxo memspent\n",(double)nValue/COIN); + } else fprintf(stderr,"couldnt find transaction\n"); } return(totalinputs); } @@ -662,7 +733,7 @@ std::string OracleCreate(int64_t txfee,std::string name,std::string description, std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee) { - CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; uint8_t buf33[33]; char markeraddr[64],batonaddr[64]; + CMutableTransaction mtx; CPubKey mypk,markerpubkey,batonpk; struct CCcontract_info *cp,C; char markeraddr[64],batonaddr[64]; cp = CCinit(&C,EVAL_ORACLES); if ( txfee == 0 ) txfee = 10000; @@ -672,11 +743,8 @@ std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee) return(""); } mypk = pubkey2pk(Mypubkey()); - buf33[0] = 0x02; - endiancpy(&buf33[1],(uint8_t *)&oracletxid,32); - markerpubkey = buf2pk(buf33); - Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG); batonpk = OracleBatonPk(batonaddr,cp); + markerpubkey = CCtxidaddr(markeraddr,oracletxid); if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 ) { mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); @@ -688,15 +756,12 @@ std::string OracleRegister(int64_t txfee,uint256 oracletxid,int64_t datafee) 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]; + CMutableTransaction mtx; CPubKey mypk,markerpubkey; struct CCcontract_info *cp,C; char markeraddr[64]; cp = CCinit(&C,EVAL_ORACLES); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - buf33[0] = 0x02; - endiancpy(&buf33[1],(uint8_t *)&oracletxid,32); - markerpubkey = buf2pk(buf33); - Getscriptaddress(markeraddr,CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG); + markerpubkey = CCtxidaddr(markeraddr,oracletxid); if ( AddNormalinputs(mtx,mypk,amount + 2*txfee,1) > 0 ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,publisher)); @@ -739,8 +804,8 @@ std::string OracleData(int64_t txfee,uint256 oracletxid,std::vector da mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,batonpk)); mtx.vout.push_back(CTxOut(datafee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeOraclesData('D',oracletxid,batontxid,mypk,data))); - } - } + } else fprintf(stderr,"couldnt find enough oracle inputs, limit 1 per utxo\n"); + } else fprintf(stderr,"couldnt add normal inputs\n"); return(""); } @@ -790,12 +855,9 @@ UniValue OracleInfo(uint256 origtxid) { UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ); std::vector > unspentOutputs; - CMutableTransaction mtx; 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 data; + CMutableTransaction mtx; CTransaction regtx,tx; std::string name,description,format; uint256 hashBlock,txid,oracletxid,batontxid; CPubKey pk; struct CCcontract_info *cp,C; int64_t datafee,funding; char str[67],markeraddr[64],numstr[64],batonaddr[64]; std::vector 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); + CCtxidaddr(markeraddr,origtxid); if ( GetTransaction(origtxid,tx,hashBlock,false) != 0 ) { if ( tx.vout.size() > 0 && DecodeOraclesCreateOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,name,description,format) == 'C' ) diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index 72e486114..ca945d02f 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -28,63 +28,60 @@ Funds work like with dice, ie. there is a Prices plan that traders bet against. - PricesOpen -> oracletxid start with 'L' price, leverage, amount - funds are locked into global CC address + PricesFunding oracletxid, margin, priceaveraging, maxleverage, funding, longtoken, shorttoken, N [pubkeys] + + PricesBet -> oracletxid start with 'L', leverage, funding, direction + funds are locked into global CC address it can be closed at anytime by the trader for cash settlement 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 riskexposure: fabs(long exposure - short exposure) + bet +B at leverage L + absval(sum(+BLi) - sum(-Bli)) + + validate: update riskexposure and it needs to be <= funds + + PricesProfits: limit withdraw to funds in excess of riskexposure + PricesFinish: payout (if winning) and update riskexposure + need long/short exposure assets + + funding -> 1of2 CC global CC address and dealer address, exposure tokens to global 1of2 assets CC address + pricebet -> user funds and exposure token to 1of2 address. + pricewin -> winnings from dealer funds, exposure token back to global address + priceloss -> exposuretoken back to global address + + exposure address, funds address */ // start of consensus code -int64_t IsPricesvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) +int64_t PricesOraclePrice(int64_t &rektprice,uint64_t mode,uint256 oracletxid,std::vectorpubkeys,int32_t dir,int64_t amount,int32_t leverage) { - char destaddr[64]; - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) - return(tx.vout[v].nValue); - } - return(0); + int64_t price; + // howto ensure price when block it confirms it not known + // get price from oracle + current chaintip + // normalize leveraged amount + if ( dir > 0 ) + rektprice = price * leverage / (leverage-1); + else rektprice = price * (leverage-1) / leverage; + return(price); } -bool PricesExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) +CScript EncodePricesFundingOpRet(uint8_t funcid,CPubKey planpk,uint256 oracletxid,uint256 longtoken,uint256 shorttoken,int32_t millimargin,uint64_t mode,int32_t maxleverage,std::vector pubkeys,uint256 bettoken) { - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant Prices from mempool"); - if ( (assetoshis= IsPricesvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + txfee"); - } - else return(true); + CScript opret; + fprintf(stderr,"implement EncodePricesFundingOpRet\n"); + return(opret); +} + +uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &oracletxid,uint256 &longtoken,uint256 &shorttoken,int32_t &millimargin,uint64_t &mode,int32_t &maxleverage,std::vector &pubkeys,uint256 &bettoken) +{ + fprintf(stderr,"implement DecodePricesFundingOpRet\n"); + return(0); } bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) @@ -107,12 +104,12 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx } } //fprintf(stderr,"check amounts\n"); - if ( PricesExactAmounts(cp,eval,tx,1,10000) == false ) + //if ( PricesExactAmounts(cp,eval,tx,1,10000) == false ) { fprintf(stderr,"Pricesget invalid amount\n"); return false; } - else + //else { txid = tx.GetHash(); memcpy(hash,&txid,sizeof(hash)); @@ -128,20 +125,20 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx // helper functions for rpc calls in rpcwallet.cpp -int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) +int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char *destaddr,uint256 tolenid,int64_t total,int32_t maxinputs) { - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; + int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr); + SetCCunspents(unspentOutputs,destaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; - // no need to prevent dup - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + // need to prevent dup + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && vout < vintx.vout.size() ) { - if ( (nValue= IsPricesvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 ) + // need to verify assetid + if ( (nValue= vintx.vout[vout].nValue) > 10000 && myIsutxo_spentinmempool(txid,vout) == 0 ) { if ( total != 0 && maxinputs != 0 ) mtx.vin.push_back(CTxIn(txid,vout,CScript())); @@ -156,69 +153,18 @@ int64_t AddPricesInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub return(totalinputs); } -/* - UniValue PriceInfo(uint256 origtxid) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR),obj(UniValue::VOBJ); - std::vector > unspentOutputs; - 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 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' ) - { - result.push_back(Pair("result","success")); - 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 >::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)); - } - } - return(result); -} - UniValue PricesList() { - UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65]; - cp = CCinit(&C,EVAL_ORACLES); + UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint64_t mode; int32_t margin,maxleverage; std::vectorpubkeys; uint256 txid,hashBlock,oracletxid,longtoken,shorttoken,bettoken; CPubKey planpk,pricespk; char str[65]; CTransaction vintx; + cp = CCinit(&C,EVAL_PRICES); + pricespk = GetUnspendable(cp,0); SetCCtxids(addressIndex,cp->normaladdr); for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { 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,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' ) { result.push_back(uint256_str(str,txid)); } @@ -226,4 +172,273 @@ UniValue PricesList() } return(result); } -*/ + +// longtoken satoshis limits long exposure +// shorttoken satoshis limits short exposure +// both must be in the 1of2 CC address with its total supply +// bettoken +std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector pubkeys) +{ + CMutableTransaction mtx; CTransaction oracletx; int64_t fullsupply,inputs,CCchange=0; uint256 hashBlock; char str[65],coinaddr[64],houseaddr[64]; CPubKey mypk,pricespk; int32_t i,N,numvouts; struct CCcontract_info *cp,C,*assetscp,C2; + if ( funding < 100*COIN || maxleverage <= 0 || maxleverage > 10000 ) + { + CCerror = "invalid parameter error"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + cp = CCinit(&C,EVAL_PRICES); + assetscp = CCinit(&C2,EVAL_ASSETS); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp,0); + if ( (N= (int32_t)pubkeys.size()) || N > 15 ) + { + fprintf(stderr,"too many pubkeys N.%d\n",N); + return(""); + } + for (i=0; i 0 ) + { + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(pricespk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodePricesFundingOpRet('F',mypk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken))); + } + else + { + CCerror = "cant find enough inputs"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + return(""); +} + +UniValue PricesInfo(uint256 fundingtxid) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); CPubKey pricespk,planpk; uint256 hashBlock,oracletxid,longtoken,shorttoken,bettoken; CTransaction vintx; int64_t balance,supply,exposure; uint64_t funding,mode; int32_t i,margin,maxleverage; char numstr[65],houseaddr[64],exposureaddr[64],str[65]; std::vectorpubkeys; struct CCcontract_info *cp,C,*assetscp,C2; + cp = CCinit(&C,EVAL_PRICES); + assetscp = CCinit(&C2,EVAL_ASSETS); + pricespk = GetUnspendable(cp,0); + if ( GetTransaction(fundingtxid,vintx,hashBlock,false) == 0 ) + { + fprintf(stderr,"cant find fundingtxid\n"); + ERR_RESULT("cant find fundingtxid"); + return(result); + } + if ( vintx.vout.size() > 0 && DecodePricesFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' ) + { + result.push_back(Pair("result","success")); + result.push_back(Pair("fundingtxid",uint256_str(str,fundingtxid))); + result.push_back(Pair("bettoken",uint256_str(str,bettoken))); + result.push_back(Pair("oracletxid",uint256_str(str,oracletxid))); + sprintf(numstr,"%.3f",(double)margin/1000); + result.push_back(Pair("profitmargin",numstr)); + result.push_back(Pair("maxleverage",maxleverage)); + result.push_back(Pair("mode",(int64_t)mode)); + for (i=0; ipubkeys; + if ( amount < 10000 ) + { + CCerror = "amount must be positive"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + cp = CCinit(&C,EVAL_PRICES); + assetscp = CCinit(&C2,EVAL_ASSETS); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp,0); + GetCCaddress(assetscp,myaddr,mypk); + if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 ) + { + fprintf(stderr,"cant find fundingtxid\n"); + return(""); + } + if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken ) + { + GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk); + if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) + { + if ( (inputs= AddTokensInputs(assetscp,mtx,myaddr,bettoken,amount,60)) >= amount ) + { + mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,amount,pricespk,planpk)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(planpk)) << OP_CHECKSIG)); + if ( inputs > amount+txfee ) + CCchange = (inputs - amount); + mtx.vout.push_back(MakeCC1vout(assetscp->evalcode,CCchange,mypk)); + // add addr2 + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',bettoken,zeroid,0,Mypubkey()))); + } + else + { + CCerror = "cant find enough bet inputs"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + } + else + { + CCerror = "cant find enough inputs"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + } + return(""); +} + +std::string PricesBet(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,int64_t amount,int32_t leverage) +{ + CMutableTransaction mtx; struct CCcontract_info *cp,C,*assetscp,C2; CPubKey pricespk,planpk,mypk; uint256 hashBlock,oracletxid,longtoken,shorttoken,tokenid,bettoken; CTransaction tx; int64_t balance,supply,exposure,inputs,inputs2,longexposure,netexposure,shortexposure,CCchange = 0,CCchange2 = 0; uint64_t funding,mode; int32_t dir,margin,maxleverage; char houseaddr[64],myaddr[64],exposureaddr[64]; std::vectorpubkeys; + if ( amount < 0 ) + { + amount = -amount; + dir = -1; + } else dir = 1; + cp = CCinit(&C,EVAL_PRICES); + assetscp = CCinit(&C2,EVAL_ASSETS); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp,0); + GetCCaddress(assetscp,myaddr,mypk); + if ( GetTransaction(fundingtxid,tx,hashBlock,false) == 0 ) + { + fprintf(stderr,"cant find fundingtxid\n"); + return(""); + } + if ( tx.vout.size() > 0 && DecodePricesFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,planpk,oracletxid,longtoken,shorttoken,margin,mode,maxleverage,pubkeys,bettoken) == 'F' && bettoken == refbettoken ) + { + if ( leverage > maxleverage || leverage < 1 ) + { + fprintf(stderr,"illegal leverage\n"); + return(""); + } + GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk); + GetCCaddress1of2(assetscp,exposureaddr,pricespk,pricespk); + if ( dir < 0 ) + tokenid = shorttoken; + else tokenid = longtoken; + exposure = leverage * amount; + longexposure = CCtoken_balance(exposureaddr,longtoken); + shortexposure = CCtoken_balance(exposureaddr,shorttoken); + netexposure = (longexposure - shortexposure + exposure*dir); + if ( netexposure < 0 ) + netexposure = -netexposure; + balance = CCtoken_balance(myaddr,bettoken) / COIN; + if ( balance < netexposure*9/10 ) // 10% extra room for dynamically closed bets in wrong direction + { + fprintf(stderr,"balance %lld < 90%% netexposure %lld, refuse bet\n",(long long)balance,(long long)netexposure); + return(""); + } + if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + { + if ( (inputs= AddTokensInputs(assetscp,mtx,houseaddr,tokenid,exposure,30)) >= exposure ) + { + if ( (inputs2= AddTokensInputs(assetscp,mtx,myaddr,bettoken,amount,30)) >= amount ) + { + mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,amount,pricespk,planpk)); + mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,exposure,pricespk,pricespk)); + if ( inputs > exposure+txfee ) + CCchange = (inputs - exposure); + if ( inputs2 > amount+txfee ) + CCchange2 = (inputs2 - amount); + mtx.vout.push_back(MakeCC1of2vout(assetscp->evalcode,CCchange,pricespk,planpk)); + mtx.vout.push_back(MakeCC1vout(assetscp->evalcode,CCchange2,mypk)); + // add addr2 and addr3 + //return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,EncodePricesExtra('T',tokenid,bettoken,zeroid,dir*leverage))); + CScript opret; + return(FinalizeCCTx(0,assetscp,mtx,mypk,txfee,opret)); + } + else + { + fprintf(stderr,"cant find enough bettoken inputs\n"); + return(""); + } + } + else + { + fprintf(stderr,"cant find enough exposure inputs\n"); + return(""); + } + } + else + { + CCerror = "cant find enough inputsB"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + } + } + return(""); +} + +UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid) +{ + UniValue result(UniValue::VOBJ); + // get height of bettxid + // get price and rekt + // get current height and price + // what about if rekt in the past? + return(result); +} + +std::string PricesFinish(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid) +{ + return(""); +} + + + diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 61f10418c..a70071af9 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -294,7 +294,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t return(true); } -uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t refsbits,uint256 reffundingtxid,uint64_t needed) +static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t refsbits,uint256 reffundingtxid,uint64_t needed) { uint8_t funcid; uint64_t sbits,nValue; uint256 fundingtxid; char str[65]; memset(&txid,0,sizeof(txid)); diff --git a/src/dpowassets b/src/dpowassets index 88e6f72b8..9bd17ff18 100755 --- a/src/dpowassets +++ b/src/dpowassets @@ -40,3 +40,6 @@ curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dp curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"VRSC\",\"freq\":10,\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"SEC\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CCL\",\"pubkey\":\"$pubkey\"}" +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"HUSH\",\"pubkey\":\"$pubkey\"}" +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"PIRATE\",\"pubkey\":\"$pubkey\"}" +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"MGNX\",\"pubkey\":\"$pubkey\"}" diff --git a/src/fiat/mgnx b/src/fiat/mgnx new file mode 100755 index 000000000..9bd85336e --- /dev/null +++ b/src/fiat/mgnx @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=MGNX $1 $2 $3 $4 $5 $6 diff --git a/src/fiat/pirate b/src/fiat/pirate new file mode 100755 index 000000000..9314209da --- /dev/null +++ b/src/fiat/pirate @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=PIRATE $1 $2 $3 $4 $5 $6 diff --git a/src/komodo_globals.h b/src/komodo_globals.h index cc5104d12..f352b5333 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -29,6 +29,7 @@ uint64_t komodo_paxtotal(); int32_t komodo_longestchain(); uint64_t komodo_maxallowed(int32_t baseid); int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max); +bool pubkey2addr(char *destaddr,uint8_t *pubkey33); pthread_mutex_t komodo_mutex; diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 1e764a603..d0ab8c078 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -202,6 +202,7 @@ const char *Notaries_elected1[][2] = {"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" }, {"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, }; +#define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9" int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp) { diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 44516ba6b..bfd59fd57 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1628,6 +1628,11 @@ void komodo_args(char *argv0) { int32_t komodo_baseid(char *origbase); extern int COINBASE_MATURITY; + if ( strcmp(ASSETCHAINS_SYMBOL,"KMD") == 0 ) + { + fprintf(stderr,"cant have assetchain named KMD\n"); + exit(0); + } if ( (port= komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL)) != 0 ) ASSETCHAINS_RPCPORT = port; else komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_P2PPORT + 1); @@ -1699,6 +1704,11 @@ void komodo_args(char *argv0) { BITCOIND_RPCPORT = GetArg("-rpcport", ASSETCHAINS_RPCPORT); //fprintf(stderr,"(%s) port.%u chain params initialized\n",ASSETCHAINS_SYMBOL,BITCOIND_RPCPORT); + if ( strcmp("PIRATE",ASSETCHAINS_SYMBOL) == 0 && ASSETCHAINS_HALVING == 77777 ) + { + ASSETCHAINS_HALVING *= 5; + fprintf(stderr,"PIRATE halving changed to %d %.1f days\n",(int32_t)ASSETCHAINS_HALVING,(double)ASSETCHAINS_HALVING/1440); + } } else BITCOIND_RPCPORT = GetArg("-rpcport", BaseParams().RPCPort()); } diff --git a/src/main.cpp b/src/main.cpp index 89aea8360..4fabaeb29 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,6 +60,8 @@ extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN,KOMODO_INSYNC,KOMODO_CON int32_t KOMODO_NEWBLOCKS; int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block); void komodo_broadcast(CBlock *pblock,int32_t limit); +void komodo_broadcast(CBlock *pblock,int32_t limit); +bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey); BlockMap mapBlockIndex; CChain chainActive; @@ -1041,6 +1043,28 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, } } +int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only +{ + static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64]; + int32_t i; + if ( didinit == 0 ) + { + uint8_t pubkey33[33]; + for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) + { + if ( i < sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) ) + decode_hex(pubkey33,33,(char *)Notaries_elected1[i][1]); + else decode_hex(pubkey33,33,(char *)CRYPTO777_PUBSECPSTR); + pubkey2addr((char *)notaryaddrs[i],(uint8_t *)pubkey33); + } + didinit = 1; + } + for (i=0; i<=sizeof(Notaries_elected1)/sizeof(*Notaries_elected1); i++) + if ( strcmp(coinaddr,notaryaddrs[i]) == 0 ) + return(1); + return(0); +} + bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state) { // Basic checks that don't depend on any context @@ -1117,9 +1141,14 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio } if ( ASSETCHAINS_PRIVATE != 0 ) { - fprintf(stderr,"private chain nValue %.8f iscoinbase.%d\n",(double)txout.nValue/COIN,iscoinbase); + //fprintf(stderr,"private chain nValue %.8f iscoinbase.%d\n",(double)txout.nValue/COIN,iscoinbase); if ( (txout.nValue > 0 && iscoinbase == 0) || tx.GetJoinSplitValueOut() > 0 ) - return state.DoS(100, error("CheckTransaction(): this is a private chain, no public allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain"); + { + char destaddr[65]; + Getscriptaddress(destaddr,txout.scriptPubKey); + if ( komodo_isnotaryvout(destaddr) == 0 ) + return state.DoS(100, error("CheckTransaction(): this is a private chain, no public allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain"); + } } if ( txout.scriptPubKey.size() > IGUANA_MAXSCRIPTSIZE ) return state.DoS(100, error("CheckTransaction(): txout.scriptPubKey.size() too big"),REJECT_INVALID, "bad-txns-vout-negative"); @@ -3375,6 +3404,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { CBlock block; if (!ReadBlockFromDisk(block, pindexDelete,1)) return AbortNode(state, "Failed to read block"); + //if ( ASSETCHAINS_SYMBOL[0] != 0 || pindexDelete->nHeight > 1400000 ) { int32_t prevMoMheight; uint256 notarizedhash,txid; komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); @@ -3626,23 +3656,34 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo // our genesis block. In practice this (probably) won't happen because of checks elsewhere. auto reorgLength = pindexOldTip ? pindexOldTip->nHeight - (pindexFork ? pindexFork->nHeight : -1) : 0; static_assert(MAX_REORG_LENGTH > 0, "We must be able to reorg some distance"); - if (reorgLength > MAX_REORG_LENGTH) { - auto msg = strprintf(_( - "A block chain reorganization has been detected that would roll back %d blocks! " - "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." - ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + - _("Reorganization details") + ":\n" + - "- " + strprintf(_("Current tip: %s, height %d, work %s"), - pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" + - "- " + strprintf(_("New tip: %s, height %d, work %s"), - pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" + - "- " + strprintf(_("Fork point: %s %s, height %d"), - ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" + - _("Please help, human!"); - LogPrintf("*** %s\n", msg); - uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); - StartShutdown(); - return false; + if (reorgLength > MAX_REORG_LENGTH) + { + int32_t notarizedht,prevMoMheight; uint256 notarizedhash,txid; + notarizedht = komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); + if ( pindexFork->nHeight < notarizedht ) + { + fprintf(stderr,"pindexFork->nHeight.%d is < notarizedht %d, so ignore it\n",(int32_t)pindexFork->nHeight,notarizedht); + pindexFork = pindexOldTip; + } + else + { + auto msg = strprintf(_( + "A block chain reorganization has been detected that would roll back %d blocks! " + "This is larger than the maximum of %d blocks, and so the node is shutting down for your safety." + ), reorgLength, MAX_REORG_LENGTH) + "\n\n" + + _("Reorganization details") + ":\n" + + "- " + strprintf(_("Current tip: %s, height %d, work %s"), + pindexOldTip->phashBlock->GetHex(), pindexOldTip->nHeight, pindexOldTip->nChainWork.GetHex()) + "\n" + + "- " + strprintf(_("New tip: %s, height %d, work %s"), + pindexMostWork->phashBlock->GetHex(), pindexMostWork->nHeight, pindexMostWork->nChainWork.GetHex()) + "\n" + + "- " + strprintf(_("Fork point: %s %s, height %d"), + ASSETCHAINS_SYMBOL,pindexFork->phashBlock->GetHex(), pindexFork->nHeight) + "\n\n" + + _("Please help, human!"); + LogPrintf("*** %s\n", msg); + uiInterface.ThreadSafeMessageBox(msg, "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; + } } // Disconnect active blocks which are no longer in the best chain. diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 687fa9ca9..e9cf54bb4 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -107,6 +107,11 @@ static UniValue ValuePoolDesc( UniValue blockheaderToJSON(const CBlockIndex* blockindex) { UniValue result(UniValue::VOBJ); + if ( blockindex == 0 ) + { + result.push_back(Pair("error", "null blockhash")); + return(result); + } result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain @@ -1372,6 +1377,8 @@ struct CompareBlocksByHeight } }; +#include + UniValue getchaintips(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -1410,17 +1417,33 @@ UniValue getchaintips(const UniValue& params, bool fHelp) /* Build up a list of chain tips. We start with the list of all known blocks, and successively remove blocks that appear as pprev of another block. */ + /*static pthread_mutex_t mutex; static int32_t didinit; + if ( didinit == 0 ) + { + pthread_mutex_init(&mutex,NULL); + didinit = 1; + } + pthread_mutex_lock(&mutex);*/ std::set setTips; + int32_t n = 0; BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex) + { + n++; setTips.insert(item.second); + } + fprintf(stderr,"iterations getchaintips %d\n",n); + n = 0; BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex) { const CBlockIndex* pprev=0; + n++; if ( item.second != 0 ) pprev = item.second->pprev; if (pprev) setTips.erase(pprev); } + fprintf(stderr,"iterations getchaintips %d\n",n); + //pthread_mutex_unlock(&mutex); // Always report the currently active tip. setTips.insert(chainActive.LastTip()); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 9d1d0b336..a8b96d758 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -141,7 +141,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_importviewingkey", 2 }, { "z_getpaymentdisclosure", 1}, { "z_getpaymentdisclosure", 2}, - // crosschain { "assetchainproof", 1}, { "crosschainproof", 1}, @@ -195,7 +194,6 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector 0 ) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address"); - + { + if ( komodo_isnotaryvout((char *)params[0].get_str().c_str()) == 0 ) + { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address"); + } + } LOCK2(cs_main, pwalletMain->cs_wallet); CBitcoinAddress address(params[0].get_str()); @@ -4857,6 +4863,8 @@ int32_t ensure_CCrequirements() #include "../cc/CClotto.h" #include "../cc/CCchannels.h" #include "../cc/CCOracles.h" +#include "../cc/CCGateways.h" +#include "../cc/CCPrices.h" UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector &pubkey) { @@ -4875,6 +4883,12 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vectorunspendableCCaddr)); sprintf(str,"%smarker",name); result.push_back(Pair(str,cp->normaladdr)); + result.push_back(Pair("GatewaysPubkey","03ea9c062b9652d8eff34879b504eda0717895d27597aaeb60347d65eed96ccb40")); + if ( _GetCCaddress(destaddr,EVAL_ASSETS,pubkey2pk(pubkey)) > 0 ) + { + sprintf(str,"%sCCassets",name); + result.push_back(Pair(str,destaddr)); + } if ( pubkey.size() == 33 ) { if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 ) @@ -4889,7 +4903,7 @@ UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector destpubkey; CPubKey pk,pk2; char destaddr[64]; + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::vector destpubkey; CPubKey pk,pk2; char destaddr[64]; cp = CCinit(&C,EVAL_CHANNELS); if ( fHelp || params.size() != 1 ) throw runtime_error("channelsaddress destpubkey\n"); @@ -4902,6 +4916,15 @@ UniValue channelsaddress(const UniValue& params, bool fHelp) result.push_back(Pair("otherpubkey", params[0].get_str())); GetCCaddress1of2(cp,destaddr,pk,pk2); result.push_back(Pair("channeladdress",destaddr)); + if ( 0 ) + { + int32_t i; + for (i=0; i<100; i++) + { + GetCCaddress1of2(cp,destaddr,pk,pk2); + fprintf(stderr,"i.%d %s\n",i,destaddr); + } + } return(result); } @@ -4920,15 +4943,25 @@ UniValue oraclesaddress(const UniValue& params, bool fHelp) UniValue pricesaddress(const UniValue& params, bool fHelp) { - struct CCcontract_info *cp,C; std::vector pubkey; + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C,*assetscp,C2; std::vector pubkey; CPubKey mypk,planpk,pricespk; char myaddr[64],houseaddr[64],exposureaddr[64]; cp = CCinit(&C,EVAL_PRICES); + assetscp = CCinit(&C2,EVAL_PRICES); if ( fHelp || params.size() > 1 ) throw runtime_error("pricesaddress [pubkey]\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"); if ( params.size() == 1 ) pubkey = ParseHex(params[0].get_str().c_str()); - return(CCaddress(cp,(char *)"Prices",pubkey)); + result = CCaddress(cp,(char *)"Prices",pubkey); + mypk = pubkey2pk(Mypubkey()); + pricespk = GetUnspendable(cp,0); + GetCCaddress(assetscp,myaddr,mypk); + GetCCaddress1of2(assetscp,houseaddr,pricespk,planpk); + GetCCaddress1of2(assetscp,exposureaddr,pricespk,pricespk); + result.push_back(Pair("myaddr",myaddr)); // for holding my asssets + result.push_back(Pair("houseaddr",houseaddr)); // globally accessible house assets + result.push_back(Pair("exposureaddr",exposureaddr)); // tracking of exposure + return(result); } UniValue pegsaddress(const UniValue& params, bool fHelp) @@ -5106,7 +5139,8 @@ UniValue channelsopen(const UniValue& params, bool fHelp) throw runtime_error("channelsopen destpubkey numpayments payment\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"); - LOCK(cs_main); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); destpub = ParseHex(params[0].get_str().c_str()); numpayments = atoi(params[1].get_str().c_str()); payment = atol(params[2].get_str().c_str()); @@ -5127,7 +5161,8 @@ UniValue channelsstop(const UniValue& params, bool fHelp) throw runtime_error("channelsstop destpubkey origtxid\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"); - LOCK(cs_main); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); destpub = ParseHex(params[0].get_str().c_str()); origtxid = Parseuint256((char *)params[1].get_str().c_str()); hex = ChannelStop(0,pubkey2pk(destpub),origtxid); @@ -5147,7 +5182,8 @@ UniValue channelspayment(const UniValue& params, bool fHelp) throw runtime_error("channelspayment prevtxid origtxid n amount\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"); - LOCK(cs_main); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); prevtxid = Parseuint256((char *)params[0].get_str().c_str()); origtxid = Parseuint256((char *)params[1].get_str().c_str()); n = atoi((char *)params[2].get_str().c_str()); @@ -5169,7 +5205,8 @@ UniValue channelscollect(const UniValue& params, bool fHelp) throw runtime_error("channelscollect paytxid origtxid n amount\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"); - LOCK(cs_main); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); paytxid = Parseuint256((char *)params[0].get_str().c_str()); origtxid = Parseuint256((char *)params[1].get_str().c_str()); n = atoi((char *)params[2].get_str().c_str()); @@ -5191,7 +5228,8 @@ UniValue channelsrefund(const UniValue& params, bool fHelp) throw runtime_error("channelsrefund stoptxid origtxid\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"); - LOCK(cs_main); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); stoptxid = Parseuint256((char *)params[0].get_str().c_str()); origtxid = Parseuint256((char *)params[1].get_str().c_str()); hex = ChannelRefund(0,stoptxid,origtxid); @@ -5386,6 +5424,188 @@ UniValue rewardsinfo(const UniValue& params, bool fHelp) 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 pubkeys; uint8_t M,N; std::string hex,coin; std::vector 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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + 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"); + for (i=0; i 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); int32_t i,claimvout,height; int64_t amount; std::string hex,coin,deposithex; uint256 bindtxid,cointxid; std::vectorproof,destpub,pubkey; + if ( fHelp || params.size() != 9 ) + throw runtime_error("gatewaysdeposit bindtxid height coin cointxid claimvout deposithex proof destpub amount\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + height = atoi((char *)params[1].get_str().c_str()); + coin = params[2].get_str(); + cointxid = Parseuint256((char *)params[3].get_str().c_str()); + claimvout = atoi((char *)params[4].get_str().c_str()); + deposithex = params[5].get_str(); + proof = ParseHex(params[6].get_str()); + destpub = ParseHex(params[7].get_str()); + amount = atof((char *)params[8].get_str().c_str()) * COIN; + if ( amount <= 0 || claimvout < 0 ) + throw runtime_error("invalid param: amount, numpks or claimvout\n"); + hex = GatewaysDeposit(0,bindtxid,height,coin,cointxid,claimvout,deposithex,proof,pubkey2pk(destpub),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,coin; uint256 bindtxid,deposittxid; std::vectordestpub; int64_t amount; + if ( fHelp || params.size() != 5 ) + throw runtime_error("gatewaysclaim bindtxid coin deposittxid destpub amount\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + deposittxid = Parseuint256((char *)params[2].get_str().c_str()); + destpub = ParseHex(params[3].get_str()); + amount = atof((char *)params[4].get_str().c_str()) * COIN; + hex = GatewaysClaim(0,bindtxid,coin,deposittxid,pubkey2pk(destpub),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); uint256 bindtxid; int64_t amount; std::string hex,coin; std::vector withdrawpub; + if ( fHelp || params.size() != 4 ) + throw runtime_error("gatewayswithdraw bindtxid coin withdrawpub amount\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + withdrawpub = ParseHex(params[2].get_str()); + amount = atof((char *)params[3].get_str().c_str()) * COIN; + hex = GatewaysWithdraw(0,bindtxid,coin,withdrawpub,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 gatewaysmarkdone(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 withdrawtxid,cointxid; std::string hex,coin; + if ( fHelp || params.size() != 1 ) + throw runtime_error("gatewaysmarkdone withdrawtxid coin cointxid\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + withdrawtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + cointxid = Parseuint256((char *)params[2].get_str().c_str()); + hex = GatewaysMarkdone(0,withdrawtxid,coin,cointxid); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt gatewaysmarkdone"); + return(result); +} + +UniValue gatewayspending(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; std::string coin; + if ( fHelp || params.size() != 2 ) + throw runtime_error("gatewayspending bindtxid coin\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"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + return(GatewaysPendingWithdraws(bindtxid,coin)); +} + +UniValue gatewaysmultisig(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 bindtxid,withtxid; std::string coin,hex; char *txidaddr; + if ( fHelp || params.size() != 2 ) + throw runtime_error("gatewaysmultisig bindtxid coin withtxid txidaddr\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + withtxid = Parseuint256((char *)params[2].get_str().c_str()); + txidaddr = (char *)params[3].get_str().c_str(); + hex = GatewaysMultisig(0,coin,bindtxid,withtxid,txidaddr); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex",hex)); + } else ERR_RESULT("couldnt gatewaysmultisig"); + return(result); +} + UniValue oracleslist(const UniValue& params, bool fHelp) { if ( fHelp || params.size() > 0 ) @@ -5413,6 +5633,8 @@ UniValue oraclesregister(const UniValue& params, bool fHelp) throw runtime_error("oraclesregister oracletxid datafee\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); txid = Parseuint256((char *)params[0].get_str().c_str()); datafee = atol((char *)params[1].get_str().c_str()); hex = OracleRegister(0,txid,datafee); @@ -5431,6 +5653,8 @@ UniValue oraclessubscribe(const UniValue& params, bool fHelp) throw runtime_error("oraclessubscribe oracletxid publisher amount\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); txid = Parseuint256((char *)params[0].get_str().c_str()); pubkey = ParseHex(params[1].get_str().c_str()); amount = atof((char *)params[2].get_str().c_str()) * COIN; @@ -5463,6 +5687,8 @@ UniValue oraclesdata(const UniValue& params, bool fHelp) throw runtime_error("oraclesdata oracletxid hexstr\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); txid = Parseuint256((char *)params[0].get_str().c_str()); data = ParseHex(params[1].get_str().c_str()); hex = OracleData(0,txid,data); @@ -5599,6 +5825,156 @@ UniValue faucetget(const UniValue& params, bool fHelp) return(result); } +UniValue priceslist(const UniValue& params, bool fHelp) +{ + if ( fHelp || params.size() > 0 ) + throw runtime_error("priceslist\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(PricesList()); +} + +UniValue pricesinfo(const UniValue& params, bool fHelp) +{ + uint256 fundingtxid; + if ( fHelp || params.size() != 1 ) + throw runtime_error("pricesinfo fundingtxid\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"); + fundingtxid = Parseuint256((char *)params[0].get_str().c_str()); + return(PricesInfo(fundingtxid)); +} + +UniValue pricescreate(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint64_t mode; int64_t funding; int32_t i,n,margin,maxleverage; std::string hex; uint256 oracletxid,longtoken,shorttoken,bettoken; std::vector pubkeys; std::vectorpubkey; + if ( fHelp || params.size() < 8 ) + throw runtime_error("pricescreate bettoken oracletxid margin mode longtoken shorttoken maxleverage funding N [pubkeys]\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + bettoken = Parseuint256((char *)params[0].get_str().c_str()); + oracletxid = Parseuint256((char *)params[1].get_str().c_str()); + margin = atof(params[2].get_str().c_str()) * 1000; + mode = atol(params[3].get_str().c_str()); + longtoken = Parseuint256((char *)params[4].get_str().c_str()); + shorttoken = Parseuint256((char *)params[5].get_str().c_str()); + maxleverage = atol(params[6].get_str().c_str()); + funding = atof(params[7].get_str().c_str()) * COIN; + n = atoi(params[8].get_str().c_str()); + if ( n > 0 ) + { + for (i=0; i 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } + else + { + ERR_RESULT("couldnt create prices funding transaction"); + } + return(result); +} + +UniValue pricesaddfunding(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount; + if ( fHelp || params.size() != 3 ) + throw runtime_error("pricesaddfunding fundingtxid bettoken amount\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + fundingtxid = Parseuint256((char *)params[0].get_str().c_str()); + bettoken = Parseuint256((char *)params[1].get_str().c_str()); + amount = atof(params[2].get_str().c_str()) * COIN; + hex = PricesAddFunding(0,bettoken,fundingtxid,amount); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } + else + { + ERR_RESULT("couldnt create pricesaddfunding transaction"); + } + return(result); +} + +UniValue pricesbet(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount; int32_t leverage; + if ( fHelp || params.size() != 4 ) + throw runtime_error("pricesbet fundingtxid bettoken amount leverage\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + fundingtxid = Parseuint256((char *)params[0].get_str().c_str()); + bettoken = Parseuint256((char *)params[1].get_str().c_str()); + amount = atof(params[2].get_str().c_str()) * COIN; + leverage = atoi(params[3].get_str().c_str()); + hex = PricesBet(0,bettoken,fundingtxid,amount,leverage); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } + else + { + ERR_RESULT("couldnt create pricesbet transaction"); + } + return(result); +} + +UniValue pricesstatus(const UniValue& params, bool fHelp) +{ + uint256 fundingtxid,bettxid,bettoken; + if ( fHelp || params.size() != 3 ) + throw runtime_error("pricesstatus fundingtxid bettoken bettxid\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"); + fundingtxid = Parseuint256((char *)params[0].get_str().c_str()); + bettoken = Parseuint256((char *)params[1].get_str().c_str()); + bettxid = Parseuint256((char *)params[2].get_str().c_str()); + return(PricesStatus(0,bettoken,fundingtxid,bettxid)); +} + +UniValue pricesfinish(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 fundingtxid,bettxid,bettoken; std::string hex; + if ( fHelp || params.size() != 3 ) + throw runtime_error("pricesfinish fundingtxid bettoken bettxid\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + fundingtxid = Parseuint256((char *)params[0].get_str().c_str()); + bettoken = Parseuint256((char *)params[1].get_str().c_str()); + bettxid = Parseuint256((char *)params[2].get_str().c_str()); + hex = PricesFinish(0,bettoken,fundingtxid,bettxid); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } + else + { + ERR_RESULT("couldnt create pricesfinish transaction"); + } + return(result); +} + UniValue dicefund(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,timeoutblocks; std::string hex; char *name; @@ -5773,7 +6149,6 @@ UniValue dicestatus(const UniValue& params, bool fHelp) UniValue dicelist(const UniValue& params, bool fHelp) { - uint256 tokenid; if ( fHelp || params.size() > 0 ) throw runtime_error("dicelist\n"); if ( ensure_CCrequirements() < 0 ) @@ -5922,6 +6297,42 @@ UniValue tokentransfer(const UniValue& params, bool fHelp) return(result); } +UniValue tokenconvert(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); std::string hex; int32_t evalcode; int64_t amount; uint256 tokenid; + if ( fHelp || params.size() != 4 ) + throw runtime_error("tokenconvert evalcode tokenid pubkey amount\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"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + evalcode = atoi(params[0].get_str().c_str()); + tokenid = Parseuint256((char *)params[1].get_str().c_str()); + std::vector pubkey(ParseHex(params[2].get_str().c_str())); + amount = atol(params[3].get_str().c_str()); + if ( tokenid == zeroid ) + { + ERR_RESULT("invalid tokenid"); + return(result); + } + if ( amount <= 0 ) + { + ERR_RESULT("amount must be positive"); + return(result); + } + hex = AssetConvert(0,tokenid,pubkey,amount,evalcode); + if (amount > 0) { + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldnt convert tokens"); + } else { + ERR_RESULT("amount must be positive"); + } + return(result); +} + UniValue tokenbid(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); int64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 70375e663..47c93545b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2121,7 +2121,7 @@ std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime) { if ( wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME ) { - LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now); + //LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now); continue; } }