Fixes
This commit is contained in:
@@ -262,6 +262,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
cc/CCtx.cpp \
|
||||
cc/CCutils.cpp \
|
||||
cc/assets.cpp \
|
||||
cc/faucet.cpp \
|
||||
cc/betprotocol.cpp \
|
||||
chain.cpp \
|
||||
checkpoints.cpp \
|
||||
|
||||
@@ -41,8 +41,7 @@ bool ValidateAssetRemainder(uint64_t remaining_price,uint64_t remaining_nValue,u
|
||||
bool SetAssetFillamounts(uint64_t &paid,uint64_t &remaining_price,uint64_t orig_nValue,uint64_t &received,uint64_t totalprice);
|
||||
uint64_t AssetValidateBuyvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,CTransaction &tx,uint256 refassetid);
|
||||
uint64_t AssetValidateSellvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,CTransaction &tx,uint256 assetid);
|
||||
bool ConstrainAssetVout(CTxOut vout,int32_t CCflag,char *cmpaddr,uint64_t nValue);
|
||||
bool AssetExactAmounts(Eval* eval,CTransaction &tx,uint256 assetid);
|
||||
bool AssetExactAmounts(uint64_t &inputs,uint64_t &outputs,Eval* eval,CTransaction &tx,uint256 assetid);
|
||||
|
||||
// CCassetstx
|
||||
uint64_t GetAssetBalance(CPubKey pk,uint256 tokenid);
|
||||
|
||||
@@ -135,7 +135,7 @@ bool GetAssetorigaddrs(char *CCaddr,char *destaddr,CTransaction& tx)
|
||||
uint64_t IsAssetvout(uint64_t &price,std::vector<uint8_t> &origpubkey,CTransaction& tx,int32_t v,uint256 refassetid)
|
||||
{
|
||||
uint256 assetid,assetid2; uint64_t nValue=0; int32_t n; uint8_t funcid;
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) // maybe check address too?
|
||||
{
|
||||
n = tx.vout.size();
|
||||
nValue = tx.vout[v].nValue;
|
||||
@@ -277,23 +277,12 @@ uint64_t AssetValidateSellvin(Eval* eval,uint64_t &tmpprice,std::vector<uint8_t>
|
||||
else return(assetoshis);
|
||||
}
|
||||
|
||||
bool ConstrainAssetVout(CTxOut vout,int32_t CCflag,char *cmpaddr,uint64_t nValue)
|
||||
bool AssetExactAmounts(uint64_t &inputs,uint64_t &outputs,Eval* eval,CTransaction &tx,uint256 assetid)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
|
||||
return(false);
|
||||
else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
|
||||
return(false);
|
||||
else if ( (nValue == 0 && vout.nValue < 10000) || nValue != vout.nValue )
|
||||
return(false);
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool AssetExactAmounts(Eval* eval,CTransaction &tx,uint256 assetid)
|
||||
{
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis; std::vector<uint8_t> tmporigpubkey; uint64_t tmpprice;
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t assetoshis; std::vector<uint8_t> tmporigpubkey; uint64_t tmpprice;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
inputs = outputs = 0;
|
||||
for (i=1; i<numvins; i++)
|
||||
{
|
||||
if ( IsAssetsInput(tx.vin[i].scriptSig) != 0 )
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
This allows creation of a special address(es) for each contract type, which has the privkey public. That allows anybody to properly sign and spend it, but with the constraints on what is allowed in the validation code, the contract functionality can be implemented.
|
||||
*/
|
||||
|
||||
CC *MakeAssetCond(CPubKey pk);
|
||||
CC *MakeFaucetCond(CPubKey pk);
|
||||
|
||||
//BTCD Address: RAssetsAtGnvwgK9gVHBbAU4sVTah1hAm5
|
||||
//BTCD Privkey: UvtvQVgVScXEYm4J3r4nE4nbFuGXSVM5pKec8VWXwgG9dmpWBuDh
|
||||
//BTCD Address: RSavingsEYcivt2DFsxsKeCjqArV6oVtVZ
|
||||
@@ -33,7 +36,9 @@
|
||||
const char *AssetsCCaddr = "RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6" ;//"RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u";
|
||||
char AssetsCChexstr[67] = { "02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702" };
|
||||
uint8_t AssetsCCpriv[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 };
|
||||
CC *MakeAssetCond(CPubKey pk);
|
||||
const char *FaucetCCaddr = "RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6" ;//"RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u";
|
||||
char FaucetCChexstr[67] = { "02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702" };
|
||||
uint8_t FaucetCCpriv[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 };
|
||||
|
||||
|
||||
bool IsAssetsInput(CScript const& scriptSig)
|
||||
@@ -53,6 +58,23 @@ bool IsAssetsInput(CScript const& scriptSig)
|
||||
return out;
|
||||
}
|
||||
|
||||
bool IsFaucetInput(CScript const& scriptSig)
|
||||
{
|
||||
CC *cond;
|
||||
if (!(cond = GetCryptoCondition(scriptSig)))
|
||||
return false;
|
||||
// Recurse the CC tree to find asset condition
|
||||
auto findEval = [&] (CC *cond, struct CCVisitor _) {
|
||||
bool r = cc_typeId(cond) == CC_Eval && cond->codeLength == 1 && cond->code[0] == EVAL_FAUCET;
|
||||
// false for a match, true for continue
|
||||
return r ? 0 : 1;
|
||||
};
|
||||
CCVisitor visitor = {findEval, (uint8_t*)"", 0, NULL};
|
||||
bool out =! cc_visit(cond, visitor);
|
||||
cc_free(cond);
|
||||
return out;
|
||||
}
|
||||
|
||||
CPubKey GetUnspendable(uint8_t evalcode,uint8_t *unspendablepriv)
|
||||
{
|
||||
static CPubKey nullpk;
|
||||
@@ -62,13 +84,20 @@ CPubKey GetUnspendable(uint8_t evalcode,uint8_t *unspendablepriv)
|
||||
{
|
||||
if ( unspendablepriv != 0 )
|
||||
memcpy(unspendablepriv,AssetsCCpriv,32);
|
||||
} else return(nullpk);
|
||||
return(pubkey2pk(ParseHex(AssetsCChexstr)));
|
||||
return(pubkey2pk(ParseHex(AssetsCChexstr)));
|
||||
}
|
||||
else if ( evalcode == EVAL_FAUCET )
|
||||
{
|
||||
if ( unspendablepriv != 0 )
|
||||
memcpy(unspendablepriv,FaucetCCpriv,32);
|
||||
return(pubkey2pk(ParseHex(FaucetCChexstr)));
|
||||
}
|
||||
else return(nullpk);
|
||||
}
|
||||
|
||||
CC *MakeCC(uint8_t evalcode,CPubKey pk)
|
||||
{
|
||||
if ( evalcode == EVAL_ASSETS )
|
||||
if ( evalcode == EVAL_ASSETS || evalcode == EVAL_FAUCET )
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
@@ -82,10 +111,10 @@ bool GetCCaddress(uint8_t evalcode,char *destaddr,CPubKey pk)
|
||||
{
|
||||
CC *payoutCond;
|
||||
destaddr[0] = 0;
|
||||
if ( pk.size() == 0 )
|
||||
pk = GetUnspendable(evalcode,0);
|
||||
if ( evalcode == EVAL_ASSETS )
|
||||
{
|
||||
if ( pk.size() == 0 )
|
||||
pk = GetUnspendable(EVAL_ASSETS,0);
|
||||
if ( (payoutCond= MakeAssetCond(pk)) != 0 )
|
||||
{
|
||||
Getscriptaddress(destaddr,CCPubKey(payoutCond));
|
||||
@@ -93,7 +122,16 @@ bool GetCCaddress(uint8_t evalcode,char *destaddr,CPubKey pk)
|
||||
}
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
fprintf(stderr,"%02x is invalid evalcode\n",evalcode);
|
||||
else if ( evalcode == EVAL_FAUCET )
|
||||
{
|
||||
if ( (payoutCond= MakeFaucetCond(pk)) != 0 )
|
||||
{
|
||||
Getscriptaddress(destaddr,CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
}
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
fprintf(stderr,"GetCCaddress %02x is invalid evalcode\n",evalcode);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
30
src/cc/CCfaucet.h
Normal file
30
src/cc/CCfaucet.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#ifndef CC_FAUCET_H
|
||||
#define CC_FAUCET_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
extern const char *FaucetCCaddr = "RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6" ;//"RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u";
|
||||
extern char FaucetCChexstr[67] = { "02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702" };
|
||||
|
||||
// CCcustom
|
||||
bool IsFaucetInput(CScript const& scriptSig);
|
||||
CC *MakeFaucetCond(CPubKey pk);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -47,6 +47,7 @@ uint256 revuint256(uint256 txid);
|
||||
char *uint256_str(char *dest,uint256 txid);
|
||||
uint256 Parseuint256(char *hexstr);
|
||||
CPubKey pubkey2pk(std::vector<uint8_t> pubkey);
|
||||
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,uint64_t nValue);
|
||||
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
|
||||
std::vector<uint8_t> Mypubkey();
|
||||
bool Myprivkey(uint8_t myprivkey[]);
|
||||
|
||||
@@ -84,6 +84,18 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,uint64_t nValue)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
|
||||
return(false);
|
||||
else if ( cmpaddr != 0 && (Getscriptaddress(destaddr,vout.scriptPubKey) == 0 || strcmp(destaddr,cmpaddr) != 0) )
|
||||
return(false);
|
||||
else if ( (nValue == 0 && vout.nValue < 10000) || nValue != vout.nValue )
|
||||
return(false);
|
||||
else return(true);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Mypubkey()
|
||||
{
|
||||
extern uint8_t NOTARY_PUBKEY33[33];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -139,7 +139,7 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
{
|
||||
if ( assetid == zero )
|
||||
return eval->Invalid("illegal assetid");
|
||||
else if ( AssetExactAmounts(eval,tx,assetid) == false )
|
||||
else if ( AssetExactAmounts(inputs,outputs,eval,tx,assetid) == false )
|
||||
eval->Invalid("asset inputs != outputs");
|
||||
}
|
||||
switch ( funcid )
|
||||
@@ -170,7 +170,7 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
// vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
|
||||
if ( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null amount for buyoffer");
|
||||
else if ( ConstrainAssetVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
return eval->Invalid("invalid vout for buyoffer");
|
||||
preventCCvins = 1;
|
||||
preventCCvouts = 1;
|
||||
@@ -187,7 +187,7 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
return(false);
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for cancelbuy");
|
||||
else if ( ConstrainAssetVout(tx.vout[0],0,origaddr,nValue) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[0],0,origaddr,nValue) == 0 )
|
||||
return eval->Invalid("invalid refund for cancelbuy");
|
||||
preventCCvins = 1;
|
||||
preventCCvouts = 0;
|
||||
@@ -212,9 +212,9 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
return eval->Invalid("mismatched origpubkeys for fillbuy");
|
||||
else
|
||||
{
|
||||
if ( ConstrainAssetVout(tx.vout[1],0,0,0) == 0 )
|
||||
if ( ConstrainVout(tx.vout[1],0,0,0) == 0 )
|
||||
return eval->Invalid("vout1 is CC for fillbuy");
|
||||
else if ( ConstrainAssetVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
return eval->Invalid("vout2 is normal for fillbuy");
|
||||
else if ( ValidateAssetRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,tmpprice) == false )
|
||||
return eval->Invalid("mismatched remainder for fillbuy");
|
||||
@@ -222,7 +222,7 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
{
|
||||
if ( remaining_price < 10000 )
|
||||
return eval->Invalid("dust vout0 to AssetsCCaddr for fillbuy");
|
||||
else if ( ConstrainAssetVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
|
||||
}
|
||||
}
|
||||
@@ -239,7 +239,7 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
//'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
|
||||
if ( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null remaining_price for selloffer");
|
||||
else if ( ConstrainAssetVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
|
||||
preventCCvouts = 1;
|
||||
break;
|
||||
@@ -254,7 +254,7 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
return(false);
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for cancel");
|
||||
else if ( ConstrainAssetVout(tx.vout[0],1,CCaddr,assetoshis) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[0],1,CCaddr,assetoshis) == 0 )
|
||||
return eval->Invalid("invalid vout for cancel");
|
||||
preventCCvins = 2;
|
||||
preventCCvouts = 1;
|
||||
@@ -275,7 +275,7 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
//'E'.vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey]
|
||||
if ( funcid == 'E' )
|
||||
{
|
||||
if ( AssetExactAmounts(eval,tx,assetid2) == false )
|
||||
if ( AssetExactAmounts(inputs,outputs,eval,tx,assetid2) == false )
|
||||
eval->Invalid("asset2 inputs != outputs");
|
||||
}
|
||||
if ( (assetoshis= AssetValidateSellvin(eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
@@ -288,17 +288,17 @@ bool AssetValidate(Eval* eval,CTransaction &tx,int32_t numvouts,uint8_t funcid,u
|
||||
{
|
||||
if ( ValidateAssetRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,tmpprice) == false )
|
||||
return eval->Invalid("mismatched remainder for fill");
|
||||
else if ( ConstrainAssetVout(tx.vout[1],1,0,0) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 )
|
||||
return eval->Invalid("normal vout1 for fillask");
|
||||
else if ( funcid == 'E' && ConstrainAssetVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
else if ( funcid == 'E' && ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
return eval->Invalid("normal vout2 for fillask");
|
||||
else if ( funcid == 'S' && ConstrainAssetVout(tx.vout[2],0,origaddr,0) == 0 )
|
||||
else if ( funcid == 'S' && ConstrainVout(tx.vout[2],0,origaddr,0) == 0 )
|
||||
return eval->Invalid("CC vout2 for fillask");
|
||||
else if ( remaining_price != 0 )
|
||||
{
|
||||
if ( remaining_price < 10000 )
|
||||
return eval->Invalid("dust vout0 to AssetsCCaddr for fill");
|
||||
else if ( ConstrainAssetVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
else if ( ConstrainVout(tx.vout[0],1,(char *)AssetsCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fill");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
#define FOREACH_EVAL(EVAL) \
|
||||
EVAL(EVAL_IMPORTPAYOUT, 0xe1) \
|
||||
EVAL(EVAL_IMPORTCOIN, 0xe2) \
|
||||
EVAL(EVAL_ASSETS, 0xe3)
|
||||
EVAL(EVAL_ASSETS, 0xe3) \
|
||||
EVAL(EVAL_FAUCET, 0xe4)
|
||||
|
||||
|
||||
typedef uint8_t EvalCode;
|
||||
@@ -267,6 +268,7 @@ typedef std::pair<uint256,MerkleBranch> TxProof;
|
||||
|
||||
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves);
|
||||
bool ProcessAssets(Eval* eval, std::vector<uint8_t> paramsNull, const CTransaction &tx, unsigned int nIn);
|
||||
bool ProcessFaucet(Eval* eval, std::vector<uint8_t> paramsNull, const CTransaction &tx, unsigned int nIn);
|
||||
|
||||
|
||||
#endif /* CC_EVAL_H */
|
||||
|
||||
132
src/cc/faucet.cpp
Normal file
132
src/cc/faucet.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCfaucet.h"
|
||||
|
||||
/*
|
||||
This file implements a simple CC faucet as an example of how to make a new CC contract. It wont have any fancy sybil protection but will serve the purpose of a fully automated faucet.
|
||||
|
||||
In order to implement a faucet, we need to have it funded. Once it is funded, anybody should be able to get some reasonable small amount.
|
||||
|
||||
This leads to needing to lock the funding in a CC protected output. And to put a spending limit. We can do a per transaction spending limit quite easily with vout constraints. However, that would allow anybody to issue thousands of transactions per block, so we also need to add a rate limiter.
|
||||
|
||||
To implement this, we can simply make any faucet vout fund the faucet. Then we can limit the number of confirmed utxo by combining faucet outputs and then only using utxo which are confirmed. This combined with a vout size limit will drastically limit the funds that can be withdrawn from the faucet.
|
||||
*/
|
||||
|
||||
CC *MakeFaucetCond(CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks; uint8_t evalcode = EVAL_ASSETS;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
CC *assetCC = CCNewEval(E_MARSHAL(ss << evalcode));
|
||||
CC *Sig = CCNewThreshold(1, pks);
|
||||
return CCNewThreshold(2, {assetCC, Sig});
|
||||
}
|
||||
|
||||
CTxOut MakeFaucetVout(CAmount nValue,CPubKey pk)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeAssetCond(pk);
|
||||
vout = CTxOut(nValue,CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
uint64_t IsFaucetvout(uint64_t &price,std::vector<uint8_t> &origpubkey,CTransaction& tx,int32_t v,uint256 refassetid)
|
||||
{
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
return(tx.vout[v].nValue);
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool FaucetExactAmounts(Eval* eval,CTransaction &tx,uint256 assetid)
|
||||
{
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis; std::vector<uint8_t> tmporigpubkey; uint64_t tmpprice;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
for (i=1; i<numvins; i++)
|
||||
{
|
||||
if ( IsFaucetInput(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("always should find vin, but didnt");
|
||||
else if ( (assetoshis= IsFaucetvout(tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 )
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
if ( (assetoshis= IsFaucetvout(tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs )
|
||||
return(false);
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool FaucetValidate(Eval* eval,CTransaction &tx)
|
||||
{
|
||||
static uint256 zero;
|
||||
CTxDestination address; CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,preventCCvins,preventCCvouts; uint64_t nValue,assetoshis,outputs,inputs,tmpprice,ignore; std::vector<uint8_t> tmporigpubkey,ignorepubkey; char destaddr[64],origaddr[64],CCaddr[64];
|
||||
fprintf(stderr,"FaucetValidate (%c)\n",funcid);
|
||||
numvins = tx.vin.size();
|
||||
outputs = inputs = 0;
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
|
||||
return eval->Invalid("illegal asset vin0");
|
||||
else if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else if ( funcid != 'c' )
|
||||
{
|
||||
if ( assetid == zero )
|
||||
return eval->Invalid("illegal assetid");
|
||||
else if ( FaucetExactAmounts(eval,tx,assetid) == false )
|
||||
eval->Invalid("asset inputs != outputs");
|
||||
}
|
||||
if ( preventCCvins >= 0 )
|
||||
{
|
||||
for (i=preventCCvins; i<numvins; i++)
|
||||
{
|
||||
if ( IsCCInput(tx.vin[i].scriptSig) != 0 )
|
||||
return eval->Invalid("invalid CC vin");
|
||||
}
|
||||
}
|
||||
if ( preventCCvouts >= 0 )
|
||||
{
|
||||
for (i=preventCCvouts; i<numvouts; i++)
|
||||
{
|
||||
if ( tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
return eval->Invalid("invalid CC vout");
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool ProcessFaucet(Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
|
||||
{
|
||||
static uint256 zero,prevtxid;
|
||||
txid = ctx.GetHash();
|
||||
if ( txid == prevtxid )
|
||||
return(true);
|
||||
CTransaction tx = *(CTransaction *)&ctx;
|
||||
if ( paramsNull.size() != 0 ) // Don't expect params
|
||||
return eval->Invalid("Cannot have params");
|
||||
else if ( tx.vout.size() == 0 )
|
||||
return eval->Invalid("no-vouts");
|
||||
if ( FaucetValidate(eval,tx,n) != 0 )
|
||||
{
|
||||
prevtxid = txid;
|
||||
return(true);
|
||||
} else return(false);
|
||||
}
|
||||
Reference in New Issue
Block a user