@@ -18,8 +18,11 @@
|
||||
#define CC_PAYMENTS_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include <gmp.h>
|
||||
|
||||
#define PAYMENTS_TXFEE 10000
|
||||
extern std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot;
|
||||
extern int32_t lastSnapShotHeight;
|
||||
|
||||
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
@@ -28,7 +31,9 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr);
|
||||
UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -74,13 +74,11 @@ CScript getCCopret(const CScript &scriptPubKey)
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
|
||||
CScript dummy; CScript opret;
|
||||
if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) )
|
||||
if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() == 1 )
|
||||
{
|
||||
//opret << E_MARSHAL(ss << vParams[0]);
|
||||
//fprintf(stderr, "vparams.%s\n", HexStr(vParams[0].begin(), vParams[0].end()).c_str());
|
||||
opret = CScript(vParams[0].begin()+6, vParams[0].end());
|
||||
}
|
||||
//fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vParams.size(), HexStr(vParams[0].begin(),vParams[0].end()).c_str());
|
||||
//opret = CScript(vParams[0].begin(), vParams[0].end());
|
||||
return opret;
|
||||
}
|
||||
|
||||
|
||||
116
src/cc/COptCCParams.cpp
Normal file
116
src/cc/COptCCParams.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*Descriptson and examples of COptCCParams class found in:
|
||||
script/standard.h/cpp
|
||||
class COptCCParams
|
||||
|
||||
structure of data in vData payload attached to end of CCvout:
|
||||
param
|
||||
OP_1
|
||||
param
|
||||
OP_2 ... etc until OP_16
|
||||
OP_PUSHDATA4 is the last OP code to tell things its at the end.
|
||||
|
||||
taken from standard.cpp line 22: COptCCParams::COptCCParams(std::vector<unsigned char> &vch)
|
||||
|
||||
EXAMPLE taken from Verus how to create scriptPubKey from COptCCParams class:
|
||||
EXAMPLE taken from Verus how to decode scriptPubKey from COptCCParams class:
|
||||
*/
|
||||
|
||||
bool MakeGuardedOutput(CAmount value, CPubKey &dest, CTransaction &stakeTx, CTxOut &vout)
|
||||
{
|
||||
CCcontract_info *cp, C;
|
||||
cp = CCinit(&C,EVAL_STAKEGUARD);
|
||||
|
||||
CPubKey ccAddress = CPubKey(ParseHex(cp->CChexstr));
|
||||
|
||||
// return an output that is bound to the stake transaction and can be spent by presenting either a signed condition by the original
|
||||
// destination address or a properly signed stake transaction of the same utxo on a fork
|
||||
vout = MakeCC1of2vout(EVAL_STAKEGUARD, value, dest, ccAddress);
|
||||
|
||||
std::vector<CPubKey> vPubKeys = std::vector<CPubKey>();
|
||||
vPubKeys.push_back(dest);
|
||||
vPubKeys.push_back(ccAddress);
|
||||
|
||||
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
|
||||
|
||||
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
|
||||
|
||||
hw << stakeTx.vin[0].prevout.hash;
|
||||
hw << stakeTx.vin[0].prevout.n;
|
||||
|
||||
uint256 utxo = hw.GetHash();
|
||||
vData.push_back(std::vector<unsigned char>(utxo.begin(), utxo.end())); // Can we use any data here to construct vector?
|
||||
|
||||
CStakeParams p;
|
||||
if (GetStakeParams(stakeTx, p))
|
||||
{
|
||||
// prev block hash and height is here to make validation easy
|
||||
vData.push_back(std::vector<unsigned char>(p.prevHash.begin(), p.prevHash.end()));
|
||||
std::vector<unsigned char> height = std::vector<unsigned char>(4);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
height[i] = (p.blkHeight >> (8 * i)) & 0xff;
|
||||
}
|
||||
vData.push_back(height);
|
||||
|
||||
COptCCParams ccp = COptCCParams(COptCCParams::VERSION, EVAL_STAKEGUARD, 1, 2, vPubKeys, vData);
|
||||
|
||||
vout.scriptPubKey << ccp.AsVector() << OP_DROP;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ValidateMatchingStake(const CTransaction &ccTx, uint32_t voutNum, const CTransaction &stakeTx, bool &cheating)
|
||||
{
|
||||
// an invalid or non-matching stake transaction cannot cheat
|
||||
cheating = false;
|
||||
|
||||
//printf("ValidateMatchingStake: ccTx.vin[0].prevout.hash: %s, ccTx.vin[0].prevout.n: %d\n", ccTx.vin[0].prevout.hash.GetHex().c_str(), ccTx.vin[0].prevout.n);
|
||||
|
||||
if (ccTx.IsCoinBase())
|
||||
{
|
||||
CStakeParams p;
|
||||
if (ValidateStakeTransaction(stakeTx, p))
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
|
||||
CScript dummy;
|
||||
|
||||
if (ccTx.vout[voutNum].scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() > 0)
|
||||
{
|
||||
COptCCParams ccp = COptCCParams(vParams[0]);
|
||||
if (ccp.IsValid() & ccp.vData.size() >= 3 && ccp.vData[2].size() <= 4)
|
||||
{
|
||||
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
|
||||
|
||||
hw << stakeTx.vin[0].prevout.hash;
|
||||
hw << stakeTx.vin[0].prevout.n;
|
||||
uint256 utxo = hw.GetHash();
|
||||
|
||||
uint32_t height = 0;
|
||||
int i, dataLen = ccp.vData[2].size();
|
||||
for (i = dataLen - 1; i >= 0; i--)
|
||||
{
|
||||
height = (height << 8) + ccp.vData[2][i];
|
||||
}
|
||||
// for debugging strange issue
|
||||
// printf("iterator: %d, height: %d, datalen: %d\n", i, height, dataLen);
|
||||
|
||||
if (utxo == uint256(ccp.vData[0]))
|
||||
{
|
||||
if (p.prevHash != uint256(ccp.vData[1]) && p.blkHeight >= height)
|
||||
{
|
||||
cheating = true;
|
||||
return true;
|
||||
}
|
||||
// if block height is equal and we are at the else, prevHash must have been equal
|
||||
else if (p.blkHeight == height)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -53,6 +53,15 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
|
||||
eval->state.GetRejectReason().data(),
|
||||
tx.vin[nIn].prevout.hash.GetHex().data());
|
||||
if (eval->state.IsError()) fprintf(stderr, "Culprit: %s\n", EncodeHexTx(tx).data());
|
||||
CTransaction tmp;
|
||||
if (mempool.lookup(tx.GetHash(), tmp))
|
||||
{
|
||||
// This is to remove a payments airdrop if it gets stuck in the mempool.
|
||||
// Miner will mine 1 invalid block, but doesnt stop them mining until a restart.
|
||||
// This would almost never happen in normal use.
|
||||
std::list<CTransaction> dummy;
|
||||
mempool.remove(tx,dummy,true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
65
src/cc/hempcoin_notes.txt
Normal file
65
src/cc/hempcoin_notes.txt
Normal file
@@ -0,0 +1,65 @@
|
||||
How this works:
|
||||
- earlytxid must be a transaction included in the chain before block 100. The chain MUST not have any other of these type of tx before block 100, or someone may be able to change it and mess things up.
|
||||
- When it gets to block 100, it takes the txid specified by the -earlytxid param (does not affect magic)
|
||||
- Looks up the transaction searches for the opreturn, then permenantly appends it to the end of ac_script in RAM.
|
||||
- After every daemon restart, the first time the daemon mines a block, or receives a block that pays ac_script it will look up the op_return and save it again.
|
||||
- this enables it to always reach consensus but doesnt need to constantly keep looking up the tx in the chain.
|
||||
- The trick is to use ac_founders=101 or higher so that nothing is ever paid to the unspendable CC address. Although it should still work without this it burns coins.
|
||||
|
||||
-ac_script can be any Global CC address you can spend to with an OP_RETURN. Here we use example of paymentsCC being used to fund a rewards plan, and a set of founders address's.
|
||||
you can get the ac_script from another chain, but the op_return payload must generated on the chain itself. this command gives you the needed info to get the scripPubKey Hex:
|
||||
./komodo-cli -ac_name=TEST paymentsfund '["5d536f54332db09f2be04593c54f764cf569e225f4d8df5155658c679e663682",1000]'
|
||||
append: b8, to the end of ac_script, this changes magic value for -earlytxid chains vs normal ac_script and allows bypass of ac_supply paid to the scritpt as it would be unspendable and you would be unable to create the needed plans with no coins.
|
||||
-ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8
|
||||
|
||||
-testnode=1 is not affecting magic and allows mining on a single node, we can use this to bootstrap the chain before syncing a second node to save time.
|
||||
|
||||
start chain and make sure to do the following steps before block 100 (set generate false/true is a good idea between steps)
|
||||
./komodod -ac_name=TESTHC -ac_supply=1000000 -ac_reward=100000000000 -ac_cc=2 -ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8 -ac_founders=150 -ac_blocktime=20 -ac_nk=96,5 -testnode=1
|
||||
|
||||
create rewards plan and fund it with all or a % of the premine. Must be some amount. eg.
|
||||
./komodo-cli -ac_name=TESTHC rewardscreatefunding test 50000 25 0 2 500
|
||||
|
||||
do rewards add funding:
|
||||
./komodo-cli -ac_name=TESTHC rewardsaddfunding test 47a3150150bd196bd2086cae5e0c6b01a23785a04139fa660d169121a534b38e 1000
|
||||
|
||||
and get the script pubkey and op_return from this tx (no need to send it)
|
||||
./komodo-cli -ac_name=TESTHC decoderawtransaction 010000000204ca4c7aaae62bb8fc9412ac010e047fa8d33c3f87d2adeb3e02170642ddfe370000000049483045022100d7b9a
|
||||
4f28ca3a35f34dcdb6075e905cde1eaa962bd0619d0a8ed8e17e952bc99022077308e12325fc2a02c752ec3df9aeee1fc219ea54a4d3884834582b75c89815e01ffffffff08800132da3233d80c65e87b6db6a76dcf
|
||||
188e4fdfa23198d69f647e67754cfb0000000049483045022100d6a8f7a1c4f6013f5897768ae0117fe61dfb72352d3e6652e64a6588db3ffcb102202aa1d041b24f9cbbf7028295b7c5e7f18b4f95ae39c13031dab
|
||||
7f06634438e6801ffffffff0300e8764817000000302ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401ccf0c0764817000000232103bbec93af84
|
||||
0933ae2d35fc56eff24f34dbe26871402552f84c44f690945ccd79ac00000000000000002c6a2ae54174657374000000008eb334a52191160d66fa3941a08537a2016b0c5eae6c08d26b19bd500115a34700000000
|
||||
|
||||
From the return of this you need the scriptpubkey hex of vout 0:
|
||||
scriptPubKey: 2ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401cc
|
||||
and the scriptpubkey hex of the OP_RETURN in vout 2.
|
||||
OP_RETURN: 6a2ae54174657374000000008eb334a52191160d66fa3941a08537a2016b0c5eae6c08d26b19bd500115a347
|
||||
|
||||
create txidopreturn for this payment:
|
||||
./komodo-cli -ac_name=TESTHC paymentstxidopret '[50,"2ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401cc","6a2ae54174657374000000008eb334a52191160d66fa3941a08537a2016b0c5eae6c08d26b19bd500115a347"]'
|
||||
|
||||
create the txidopret for the founders reward(s) pubkeys: should be able to be a few here, not sure of max number yet. These can pay anything that does not need an opreturn. allocation and scriptpubkey hex.
|
||||
./komodo-cli -ac_name=TESTHC paymentstxidopret '[50,"76a9146bf5dd9f679c87a3f83ea176f82148d26653c04388ac"]'
|
||||
|
||||
create payments plan:
|
||||
./komodo-cli -ac_name=TESTHC paymentscreate '[0,0,"61f55f2f87dad3a37d42731a8cb73b3ebea1817abfa176218162c360a8bd7145","0550014823ffa0aa99d7dd7ca5292f4dd0a1b9156eddec03412c953f095181bc"]'
|
||||
gives plan txid: ee7765be874fb084c00538b1b0488e8ecb857de253f09a9ba6ea8d3579b77d33
|
||||
|
||||
paymentsfund:
|
||||
To do this you first need to change the type of tx generated by paymentsfund RPC. in payments.cpp go to line: 639 and comment it out, then uncomment the block of code under this.
|
||||
change the line 646 to line 647 with comments, and line 650/651 aswell. This enables the RPC to generate the ccvout opreturn payload you need without sending the payment on the chain. Just decode the raw hex.
|
||||
./komodo-cli -ac_name=TESTHC paymentsfund '["ee7765be874fb084c00538b1b0488e8ecb857de253f09a9ba6ea8d3579b77d33",1000,1]'
|
||||
|
||||
get the payment fund scriptpubkey hex from vout 0: (the split it at OP_CHECKCRYPTOCONDITION or 'cc' )
|
||||
2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401cc 2a0401f00101246a22f046337db779358deaa69b9af053e27d85cb8e8e48b0b13805c084b04f87be6577ee75
|
||||
|
||||
put the second half into an OP_RETURN: (the remaining part of the the above scriptpubkey) eg.
|
||||
./komodo-cli -ac_name=TESTHC opreturn_burn 1 2a0401f00101246a22f046337db779358deaa69b9af053e27d85cb8e8e48b0b13805c084b04f87be6577ee75
|
||||
opret_burn takes any burn amount and arbitrary hex string. (RPC works, but may have bugs, likely use this for LABS too with some fixes)
|
||||
this gives a raw hex. Decode it and check the OP_RETURN is right before sending.
|
||||
-earlytxid=810bd62fb8353fad20267ff2050684b8829affa3edf6b366633931530791dfce
|
||||
restart the chain with earlytxid param before height 100 on all nodes (if not using -testnode=1)
|
||||
./komodod -ac_name=TESTHC -ac_supply=1000000 -ac_reward=100000000000 -ac_cc=2 -ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8 -ac_founders=150 -ac_blocktime=20 -ac_nk=96,5 -earlytxid=810bd62fb8353fad20267ff2050684b8829affa3edf6b366633931530791dfce
|
||||
|
||||
once the payments plan has been funded with the mined coinbase you can issue payments release when conditions of the plan are met to fund founders reward/rewards plan. eg.
|
||||
./komodo-cli -ac_name=TESTHC paymentsrelease '["ee7765be874fb084c00538b1b0488e8ecb857de253f09a9ba6ea8d3579b77d33",500]'
|
||||
@@ -16,12 +16,6 @@
|
||||
#include "CCPayments.h"
|
||||
|
||||
/*
|
||||
|
||||
-earlytxid is not an -ac_param, so it doesnt affect the chain magics
|
||||
extra data after the normal CCvout is whatever data we want and can represent whatever we want
|
||||
so -ac_script=<payments CC vout + useearlytxid>
|
||||
in the validation if you see the useearlytxid in the opreturn data or extra data, you use the earlytxid as the txid that specifies the payment
|
||||
|
||||
0) txidopret <- allocation, scriptPubKey, opret
|
||||
1) create <- locked_blocks, minrelease, list of txidopret
|
||||
|
||||
@@ -123,6 +117,26 @@ uint8_t DecodePaymentsFundOpRet(CScript scriptPubKey,uint256 &checktxid)
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodePaymentsMergeOpRet(uint256 checktxid)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'M' << checktxid);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodePaymentsMergeOpRet(CScript scriptPubKey,uint256 &checktxid)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> checktxid) != 0 )
|
||||
{
|
||||
if ( e == EVAL_PAYMENTS && f == 'M' )
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodePaymentsOpRet(int32_t lockedblocks,int32_t minrelease,int64_t totalallocations,std::vector<uint256> txidoprets)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
|
||||
@@ -137,12 +151,52 @@ uint8_t DecodePaymentsOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> totalallocations; ss >> txidoprets) != 0 )
|
||||
{
|
||||
if ( e == EVAL_PAYMENTS && f == 'C' )
|
||||
if ( e == EVAL_PAYMENTS && f == 'C' && txidoprets.size() > 1 )
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,int32_t bottom,int8_t fixedAmount,std::vector<std::vector<uint8_t>> excludeScriptPubKeys)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << top << bottom << fixedAmount << excludeScriptPubKeys);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodePaymentsSnapsShotOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &top,int32_t &bottom,int8_t &fixedAmount,std::vector<std::vector<uint8_t>> &excludeScriptPubKeys)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> top; ; ss >> bottom; ss >> fixedAmount; ss >> excludeScriptPubKeys) != 0 )
|
||||
{
|
||||
if ( e == EVAL_PAYMENTS && f == 'S' )
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodePaymentsTokensOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,std::vector<std::vector<uint8_t>> excludeScriptPubKeys, uint256 tokenid)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'O' << lockedblocks << minrelease << top << excludeScriptPubKeys << tokenid);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodePaymentsTokensOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &top,std::vector<std::vector<uint8_t>> &excludeScriptPubKeys, uint256 &tokenid)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> top; ss >> excludeScriptPubKeys; ss >> tokenid) != 0 )
|
||||
{
|
||||
if ( e == EVAL_PAYMENTS && f == 'O' )
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr)
|
||||
{
|
||||
char destaddr[64];
|
||||
@@ -177,8 +231,10 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
// change is/must be in vout[0]
|
||||
// only 'F' or 1of2 txidaddr can be spent
|
||||
// all vouts must match exactly
|
||||
char temp[128], coinaddr[64], txidaddr[64]; std::string scriptpubkey; uint256 createtxid, blockhash; CTransaction tmptx;
|
||||
char temp[128], coinaddr[64], txidaddr[64]; std::string scriptpubkey; uint256 createtxid, blockhash, tokenid; CTransaction plantx; int8_t funcid=0, fixedAmount=0;
|
||||
int32_t i,lockedblocks,minrelease; int64_t change,totalallocations; std::vector<uint256> txidoprets; bool fHasOpret = false; CPubKey txidpk,Paymentspk;
|
||||
int32_t top,bottom=0; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; bool fFixedAmount = false;
|
||||
mpz_t mpzTotalAllocations, mpzAllocation;; mpz_init(mpzTotalAllocations);
|
||||
// user marker vout to get the createtxid
|
||||
if ( tx.vout.size() < 2 )
|
||||
return(eval->Invalid("not enough vouts"));
|
||||
@@ -193,13 +249,15 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
//printf("createtxid.%s\n",createtxid.ToString().c_str());
|
||||
|
||||
// use the createtxid to fetch the tx and all of the plans info.
|
||||
if ( myGetTransaction(createtxid,tmptx,blockhash) != 0 )
|
||||
{
|
||||
if ( tmptx.vout.size() > 0 && DecodePaymentsOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 )
|
||||
if ( myGetTransaction(createtxid,plantx,blockhash) != 0 && plantx.vout.size() > 0 )
|
||||
{
|
||||
if ( ((funcid= DecodePaymentsOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets)) == 'C' || (funcid= DecodePaymentsSnapsShotOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') )
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
|
||||
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) )
|
||||
return(eval->Invalid("negative values"));
|
||||
Paymentspk = GetUnspendable(cp,0);
|
||||
txidpk = CCtxidaddr(txidaddr,createtxid);
|
||||
GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk);
|
||||
//fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() );
|
||||
if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) )
|
||||
return eval->Invalid("txfee is too high");
|
||||
@@ -208,65 +266,137 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
std::vector<CScript> scriptPubKeys;
|
||||
int64_t checkallocations = 0;
|
||||
i = 0;
|
||||
BOOST_FOREACH(const uint256& txidopret, txidoprets)
|
||||
if ( funcid == 'C' )
|
||||
{
|
||||
CTransaction tx0; std::vector<uint8_t> scriptPubKey,opret; int64_t allocation;
|
||||
if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
|
||||
// normal payment
|
||||
for (const uint256& txidopret : txidoprets)
|
||||
{
|
||||
scriptPubKeys.push_back(CScript(scriptPubKey.begin(), scriptPubKey.end()));
|
||||
allocations.push_back(allocation);
|
||||
//fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation);
|
||||
checkallocations += allocation;
|
||||
// if we have an op_return to pay to need to check it exists and is paying the correct opret.
|
||||
if ( !opret.empty() )
|
||||
CTransaction tx0; std::vector<uint8_t> scriptPubKey,opret; int64_t allocation;
|
||||
if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
|
||||
{
|
||||
if ( !fHasOpret )
|
||||
scriptPubKeys.push_back(CScript(scriptPubKey.begin(), scriptPubKey.end()));
|
||||
allocations.push_back(allocation);
|
||||
//fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation);
|
||||
checkallocations += allocation;
|
||||
// if we have an op_return to pay to need to check it exists and is paying the correct opret.
|
||||
if ( !opret.empty() )
|
||||
{
|
||||
fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str());
|
||||
return(eval->Invalid("missing opret in payments release"));
|
||||
}
|
||||
else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey )
|
||||
{
|
||||
fprintf(stderr, "opret.%s vs opret.%s\n",HexStr(opret.begin(), opret.end()).c_str(), HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin(), tx.vout[tx.vout.size()-1].scriptPubKey.end()).c_str());
|
||||
return(eval->Invalid("pays incorrect opret"));
|
||||
if ( !fHasOpret )
|
||||
{
|
||||
fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str());
|
||||
return(eval->Invalid("missing opret in payments release"));
|
||||
}
|
||||
else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey )
|
||||
{
|
||||
fprintf(stderr, "opret.%s vs opret.%s\n",HexStr(opret.begin(), opret.end()).c_str(), HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin(), tx.vout[tx.vout.size()-1].scriptPubKey.end()).c_str());
|
||||
return(eval->Invalid("pays incorrect opret"));
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
mpz_set_si(mpzTotalAllocations,totalallocations);
|
||||
}
|
||||
else if ( funcid == 'S' )
|
||||
{
|
||||
if ( KOMODO_SNAPSHOT_INTERVAL == 0 )
|
||||
return(eval->Invalid("snapshots not activated on this chain"));
|
||||
if ( vAddressSnapshot.size() == 0 )
|
||||
return(eval->Invalid("need first snapshot"));
|
||||
// need time for TX to me mined before the next snapshot.
|
||||
if ( top > 3999 )
|
||||
return(eval->Invalid("transaction too big"));
|
||||
if ( fixedAmount == 7 )
|
||||
{
|
||||
// game setting, randomise bottom and top values
|
||||
uint64_t x;
|
||||
uint256 tmphash = chainActive[lastSnapShotHeight]->GetBlockHash();
|
||||
memcpy(&x,&tmphash,sizeof(x));
|
||||
bottom = ((x & 0xff) % 50);
|
||||
if ( bottom == 0 ) bottom = 1;
|
||||
top = (((x>>8) & 0xff) % 100);
|
||||
if ( top < 50 ) top += 50;
|
||||
bottom = (vAddressSnapshot.size()*bottom)/100;
|
||||
top = (vAddressSnapshot.size()*top)/100;
|
||||
fprintf(stderr, "bottom.%i top.%i\n",bottom,top);
|
||||
fFixedAmount = true;
|
||||
}
|
||||
else if ( fixedAmount != 0 )
|
||||
{
|
||||
fFixedAmount = true;
|
||||
}
|
||||
for (int32_t j = bottom; j < vAddressSnapshot.size(); j++)
|
||||
{
|
||||
auto &address = vAddressSnapshot[j];
|
||||
CScript scriptPubKey = GetScriptForDestination(address.second); bool skip = false;
|
||||
for ( auto skipkey : excludeScriptPubKeys )
|
||||
{
|
||||
if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) )
|
||||
{
|
||||
skip = true;
|
||||
//fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str());
|
||||
}
|
||||
}
|
||||
if ( !skip )
|
||||
{
|
||||
mpz_init(mpzAllocation);
|
||||
i++;
|
||||
scriptPubKeys.push_back(scriptPubKey);
|
||||
allocations.push_back(address.first);
|
||||
mpz_set_si(mpzAllocation,address.first);
|
||||
mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation);
|
||||
mpz_clear(mpzAllocation);
|
||||
}
|
||||
if ( i+bottom == top ) // we reached top amount to pay, it can be less than this!
|
||||
break;
|
||||
}
|
||||
if ( i != tx.vout.size()-2 )
|
||||
return(eval->Invalid("pays wrong amount of recipients"));
|
||||
}
|
||||
else if ( funcid == 'O' )
|
||||
{
|
||||
// tokens snapshot.
|
||||
}
|
||||
|
||||
// sanity check to make sure we got all the required info
|
||||
//fprintf(stderr, " allocations.size().%li scriptPubKeys.size.%li\n",allocations.size(), scriptPubKeys.size());
|
||||
if ( allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size() )
|
||||
return(eval->Invalid("missing data cannot validate"));
|
||||
|
||||
//fprintf(stderr, "totalallocations.%li checkallocations.%li\n",totalallocations, checkallocations);
|
||||
if ( totalallocations != checkallocations )
|
||||
if ( funcid == 'C' && totalallocations != checkallocations ) // only check for normal payments release.
|
||||
return(eval->Invalid("allocation missmatch"));
|
||||
|
||||
txidpk = CCtxidaddr(txidaddr,createtxid);
|
||||
GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk);
|
||||
//fprintf(stderr, "coinaddr.%s\n", coinaddr);
|
||||
|
||||
|
||||
// make sure change is in vout 0 and is paying to the contract address.
|
||||
if ( (change= IsPaymentsvout(cp,tx,0,coinaddr)) == 0 )
|
||||
return(eval->Invalid("change is in wrong vout or is wrong tx type"));
|
||||
|
||||
// Check vouts go to the right place and pay the right amounts.
|
||||
int64_t amount = 0, checkamount; int32_t n = 0;
|
||||
int64_t amount = 0, checkamount; int32_t n = 0;
|
||||
checkamount = tx.GetValueOut() - change - PAYMENTS_TXFEE;
|
||||
mpz_t mpzCheckamount; mpz_init(mpzCheckamount); mpz_set_si(mpzCheckamount,checkamount);
|
||||
for (i = 1; i < (fHasOpret ? tx.vout.size()-2 : tx.vout.size()-1); i++)
|
||||
{
|
||||
std::string destscriptPubKey = HexStr(scriptPubKeys[n].begin(),scriptPubKeys[n].end());
|
||||
std::string voutscriptPubKey = HexStr(tx.vout[i].scriptPubKey.begin(),tx.vout[i].scriptPubKey.end());
|
||||
if ( destscriptPubKey != voutscriptPubKey )
|
||||
if ( scriptPubKeys[n] != tx.vout[i].scriptPubKey )
|
||||
{
|
||||
fprintf(stderr, "pays wrong destination destscriptPubKey.%s voutscriptPubKey.%s\n", destscriptPubKey.c_str(), voutscriptPubKey.c_str());
|
||||
fprintf(stderr, "pays wrong destination destscriptPubKey.%s voutscriptPubKey.%s\n", HexStr(scriptPubKeys[n].begin(),scriptPubKeys[n].end()).c_str(), HexStr(tx.vout[i].scriptPubKey.begin(),tx.vout[i].scriptPubKey.end()).c_str());
|
||||
return(eval->Invalid("pays wrong address"));
|
||||
}
|
||||
int64_t test = allocations[n];
|
||||
test *= checkamount;
|
||||
test /= totalallocations;
|
||||
if ( test != tx.vout[i].nValue && test != tx.vout[i].nValue-1 )
|
||||
int64_t test;
|
||||
if ( fFixedAmount )
|
||||
{
|
||||
test = checkamount / (top-bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
mpz_init(mpzAllocation);
|
||||
mpz_set_si(mpzAllocation,allocations[n]);
|
||||
mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount);
|
||||
mpz_cdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations);
|
||||
test = mpz_get_si(mpzAllocation);
|
||||
mpz_clear(mpzAllocation);
|
||||
}
|
||||
// Vairance of 1 sat is allowed, for rounding errors.
|
||||
if ( test >= tx.vout[i].nValue+1 && test <= tx.vout[i].nValue-1 )
|
||||
{
|
||||
fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue);
|
||||
return(eval->Invalid("amounts do not match"));
|
||||
@@ -274,6 +404,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
amount += tx.vout[i].nValue;
|
||||
n++;
|
||||
}
|
||||
mpz_clear(mpzTotalAllocations);
|
||||
// This is a backup check to make sure there are no extra vouts paying something else!
|
||||
if ( checkamount != amount )
|
||||
return(eval->Invalid("amounts do not match"));
|
||||
@@ -284,6 +415,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
return(eval->Invalid("amount is too small"));
|
||||
}
|
||||
|
||||
// Check vins
|
||||
i = 0;
|
||||
int32_t ht = chainActive.LastTip()->GetHeight();
|
||||
BOOST_FOREACH(const CTxIn& vin, tx.vin)
|
||||
@@ -296,17 +428,12 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey);
|
||||
if ( strcmp(destaddr,coinaddr) != 0 )
|
||||
{
|
||||
// if does not come from address its in the global payments adddress and we need to check the opreturn.
|
||||
CScript opret; uint256 checktxid; int32_t opret_ind;
|
||||
if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 )
|
||||
{
|
||||
// get op_return from CCvout
|
||||
opret = getCCopret(txin.vout[0].scriptPubKey);
|
||||
}
|
||||
opret = getCCopret(txin.vout[vin.prevout.n].scriptPubKey); // get op_return from CCvout,
|
||||
else
|
||||
{
|
||||
// get op_return from the op_return
|
||||
opret = txin.vout[opret_ind].scriptPubKey;
|
||||
} // else return(eval->Invalid("vin has wrong amount of vouts")); // dont think this is needed?
|
||||
opret = txin.vout[opret_ind].scriptPubKey;
|
||||
if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid )
|
||||
{
|
||||
fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str());
|
||||
@@ -333,7 +460,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
|
||||
int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey txidpk,int64_t total,int32_t maxinputs,uint256 createtxid,int32_t latestheight)
|
||||
{
|
||||
char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx,tx; int32_t iter,vout,ht,n = 0;
|
||||
char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t iter,vout,ht,n = 0;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
if ( maxinputs > CC_MAXVINS )
|
||||
maxinputs = CC_MAXVINS;
|
||||
@@ -352,7 +479,7 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
|
||||
txid = it->first.txhash;
|
||||
vout = (int32_t)it->first.index;
|
||||
//fprintf(stderr,"iter.%d %s/v%d %s\n",iter,txid.GetHex().c_str(),vout,coinaddr);
|
||||
if ( vout == 0 && GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
if ( (vout == 0 || vout == 1) && GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( latestheight != 0 )
|
||||
{
|
||||
@@ -373,14 +500,14 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
|
||||
if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 )
|
||||
{
|
||||
// get op_return from CCvout
|
||||
opret = getCCopret(vintx.vout[0].scriptPubKey);
|
||||
opret = getCCopret(vintx.vout[vout].scriptPubKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get op_return from the op_return
|
||||
opret = vintx.vout[opret_ind].scriptPubKey;
|
||||
}
|
||||
if ( myGetTransaction(txid,tx,hashBlock) == 0 || DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid )
|
||||
if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid )
|
||||
{
|
||||
fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str());
|
||||
continue;
|
||||
@@ -397,6 +524,7 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
|
||||
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
|
||||
break;
|
||||
} //else fprintf(stderr,"nValue %.8f vs threshold %.8f\n",(double)nValue/COIN,(double)threshold/COIN);
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -475,8 +603,10 @@ int32_t payments_parsehexdata(std::vector<uint8_t> &hexdata,cJSON *item,int32_t
|
||||
UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
|
||||
{
|
||||
int32_t latestheight,nextheight = komodo_nextheight();
|
||||
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock;
|
||||
CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease; int64_t newamount,inputsum,amount,CCchange=0,totalallocations,checkallocations=0,allocation; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector<uint256> txidoprets;
|
||||
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock,tokenid;
|
||||
CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease; int64_t newamount,inputsum,amount,CCchange=0,totalallocations=0,checkallocations=0,allocation; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector<uint256> txidoprets;
|
||||
int32_t top,bottom=0; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t funcid,fixedAmount=0; bool fFixedAmount = false;
|
||||
mpz_t mpzTotalAllocations; mpz_init(mpzTotalAllocations);
|
||||
cJSON *params = payments_reparse(&n,jsonstr);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
Paymentspk = GetUnspendable(cp,0);
|
||||
@@ -484,14 +614,16 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
|
||||
{
|
||||
createtxid = payments_juint256(jitem(params,0));
|
||||
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049;
|
||||
if ( myGetTransaction(createtxid,tx,hashBlock) != 0 )
|
||||
if ( myGetTransaction(createtxid,tx,hashBlock) != 0 && tx.vout.size() > 0 )
|
||||
{
|
||||
if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 )
|
||||
if ( ((funcid= DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets)) == 'C' || (funcid= DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') )
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
|
||||
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","negative parameter"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
latestheight = (nextheight - lockedblocks - 1);
|
||||
@@ -501,94 +633,209 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
|
||||
result.push_back(Pair("error","amount too smal"));
|
||||
result.push_back(Pair("amount",ValueFromAmount(amount)));
|
||||
result.push_back(Pair("minrelease",ValueFromAmount(minrelease*COIN)));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
txidpk = CCtxidaddr(txidaddr,createtxid);
|
||||
mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk));
|
||||
m = txidoprets.size();
|
||||
for (i=0; i<m; i++)
|
||||
//fprintf(stderr, "funcid.%i\n", funcid);
|
||||
if ( funcid == 'C' )
|
||||
{
|
||||
std::vector<uint8_t> scriptPubKey,opret;
|
||||
vout.nValue = 0;
|
||||
if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
|
||||
// normal payments
|
||||
for (i=0; i<m; i++)
|
||||
{
|
||||
vout.nValue = allocation;
|
||||
vout.scriptPubKey.resize(scriptPubKey.size());
|
||||
memcpy(&vout.scriptPubKey[0],&scriptPubKey[0],scriptPubKey.size());
|
||||
checkallocations += allocation;
|
||||
if ( opret.size() > 0 )
|
||||
std::vector<uint8_t> scriptPubKey,opret;
|
||||
vout.nValue = 0;
|
||||
if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
|
||||
{
|
||||
onlyopret.resize(opret.size());
|
||||
memcpy(&onlyopret[0],&opret[0],opret.size());
|
||||
numoprets++;
|
||||
vout.nValue = allocation;
|
||||
vout.scriptPubKey.resize(scriptPubKey.size());
|
||||
memcpy(&vout.scriptPubKey[0],&scriptPubKey[0],scriptPubKey.size());
|
||||
checkallocations += allocation;
|
||||
if ( opret.size() > 0 )
|
||||
{
|
||||
onlyopret.resize(opret.size());
|
||||
memcpy(&onlyopret[0],&opret[0],opret.size());
|
||||
numoprets++;
|
||||
}
|
||||
} else break;
|
||||
mtx.vout.push_back(vout);
|
||||
}
|
||||
result.push_back(Pair("numoprets",(int64_t)numoprets));
|
||||
if ( i != m )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid txidoprets[i]"));
|
||||
result.push_back(Pair("txi",(int64_t)i));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
else if ( checkallocations != totalallocations )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","totalallocations mismatch"));
|
||||
result.push_back(Pair("checkallocations",(int64_t)checkallocations));
|
||||
result.push_back(Pair("totalallocations",(int64_t)totalallocations));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
else if ( numoprets > 1 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","too many oprets"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
// set totalallocations to a mpz_t bignum, for amounts calculation later.
|
||||
mpz_set_si(mpzTotalAllocations,totalallocations);
|
||||
}
|
||||
else if ( funcid == 'S' )
|
||||
{
|
||||
// normal snapshot
|
||||
if ( vAddressSnapshot.size() == 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","first snapshot has not happened yet"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
if ( top > 3999 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","cannot pay more than 3999 addresses"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
i = 0;
|
||||
//for ( auto address : vAddressSnapshot )
|
||||
if ( fixedAmount == 7 )
|
||||
{
|
||||
// game setting, randomise bottom and top values
|
||||
uint64_t x;
|
||||
uint256 tmphash = chainActive[lastSnapShotHeight]->GetBlockHash();
|
||||
memcpy(&x,&tmphash,sizeof(x));
|
||||
bottom = ((x & 0xff) % 50);
|
||||
if ( bottom == 0 ) bottom = 1;
|
||||
top = (((x>>8) & 0xff) % 100);
|
||||
if ( top < 50 ) top += 50;
|
||||
bottom = (vAddressSnapshot.size()*bottom)/100;
|
||||
top = (vAddressSnapshot.size()*top)/100;
|
||||
fprintf(stderr, "bottom.%i top.%i\n",bottom,top);
|
||||
fFixedAmount = true;
|
||||
}
|
||||
else if ( fixedAmount != 0 )
|
||||
{
|
||||
fFixedAmount = true;
|
||||
}
|
||||
for (int32_t j = bottom; j < vAddressSnapshot.size(); j++)
|
||||
{
|
||||
auto &address = vAddressSnapshot[j];
|
||||
CScript scriptPubKey = GetScriptForDestination(address.second); bool skip = false;
|
||||
for ( auto skipkey : excludeScriptPubKeys )
|
||||
{
|
||||
if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) )
|
||||
{
|
||||
skip = true;
|
||||
//fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str());
|
||||
}
|
||||
}
|
||||
} else break;
|
||||
mtx.vout.push_back(vout);
|
||||
if ( !skip )
|
||||
{
|
||||
mpz_t mpzAllocation; mpz_init(mpzAllocation);
|
||||
i++;
|
||||
//fprintf(stderr, "address: %s nValue.%li \n", CBitcoinAddress(address.second).ToString().c_str(), address.first);
|
||||
vout.nValue = address.first;
|
||||
vout.scriptPubKey = scriptPubKey;
|
||||
mpz_set_si(mpzAllocation,address.first);
|
||||
mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation);
|
||||
mtx.vout.push_back(vout);
|
||||
mpz_clear(mpzAllocation);
|
||||
}
|
||||
if ( i+bottom == top ) // we reached top amount to pay, it can be less than this!
|
||||
break;
|
||||
}
|
||||
m = i; // this is the amount we got, either top, or all of the address on the chain.
|
||||
}
|
||||
result.push_back(Pair("numoprets",(int64_t)numoprets));
|
||||
if ( i != m )
|
||||
else if ( funcid == 'O' )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid txidoprets[i]"));
|
||||
result.push_back(Pair("txi",(int64_t)i));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
else if ( checkallocations != totalallocations )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","totalallocations mismatch"));
|
||||
result.push_back(Pair("checkallocations",(int64_t)checkallocations));
|
||||
result.push_back(Pair("totalallocations",(int64_t)totalallocations));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
else if ( numoprets > 1 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","too many oprets"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
// token snapshot
|
||||
}
|
||||
newamount = amount;
|
||||
int64_t totalamountsent = 0;
|
||||
mpz_t mpzAmount; mpz_init(mpzAmount); mpz_set_si(mpzAmount,amount);
|
||||
fprintf(stderr, "m.%i\n",m);
|
||||
for (i=0; i<m; i++)
|
||||
{
|
||||
mtx.vout[i+1].nValue *= amount;
|
||||
mtx.vout[i+1].nValue /= totalallocations;
|
||||
mpz_t mpzValue; mpz_init(mpzValue);
|
||||
if ( fFixedAmount )
|
||||
{
|
||||
mtx.vout[i+1].nValue = amount / (top-bottom);
|
||||
//fprintf(stderr, "amount.%li / top-bottom.%i = value.%li\n", amount, (top-bottom-2), mtx.vout[i+1].nValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
mpz_set_si(mpzValue,mtx.vout[i+1].nValue);
|
||||
mpz_mul(mpzValue,mpzValue,mpzAmount);
|
||||
mpz_cdiv_q(mpzValue,mpzValue,mpzTotalAllocations);
|
||||
if ( mpz_fits_slong_p(mpzValue) )
|
||||
mtx.vout[i+1].nValue = mpz_get_si(mpzValue);
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","value too big, try releasing a smaller amount"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "nValue.%li \n", mtx.vout[i+1].nValue);
|
||||
mpz_clear(mpzValue);
|
||||
/*
|
||||
replace this with default dust threshold of 10ksat
|
||||
if ( mtx.vout[i+1].nValue < PAYMENTS_TXFEE )
|
||||
{
|
||||
newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue);
|
||||
mtx.vout[i+1].nValue = PAYMENTS_TXFEE;
|
||||
}
|
||||
} */
|
||||
totalamountsent += mtx.vout[i+1].nValue;
|
||||
}
|
||||
if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE )
|
||||
{
|
||||
std::string rawtx;
|
||||
if ( (CCchange= (inputsum - newamount - 2*PAYMENTS_TXFEE)) >= PAYMENTS_TXFEE )
|
||||
mtx.vout[0].nValue = CCchange;
|
||||
mtx.vout.push_back(CTxOut(PAYMENTS_TXFEE,CScript() << ParseHex(HexStr(txidpk)) << OP_CHECKSIG));
|
||||
GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk);
|
||||
CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr);
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret);
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
result.push_back(Pair("amount",ValueFromAmount(amount)));
|
||||
result.push_back(Pair("newamount",ValueFromAmount(newamount)));
|
||||
return(payments_rawtxresult(result,rawtx,1));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt find enough locked funds"));
|
||||
}
|
||||
if ( totalamountsent < amount ) newamount = totalamountsent;
|
||||
fprintf(stderr, "newamount.%li totalamountsent.%li\n", newamount, totalamountsent);
|
||||
mpz_clear(mpzAmount); mpz_clear(mpzTotalAllocations);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt decode paymentscreate txid opret"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE )
|
||||
{
|
||||
std::string rawtx;
|
||||
if ( (CCchange= (inputsum - newamount - 2*PAYMENTS_TXFEE)) >= PAYMENTS_TXFEE )
|
||||
mtx.vout[0].nValue = CCchange;
|
||||
mtx.vout.push_back(CTxOut(PAYMENTS_TXFEE,CScript() << ParseHex(HexStr(txidpk)) << OP_CHECKSIG));
|
||||
GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk);
|
||||
CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr);
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret);
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
result.push_back(Pair("amount",ValueFromAmount(amount)));
|
||||
result.push_back(Pair("newamount",ValueFromAmount(newamount)));
|
||||
return(payments_rawtxresult(result,rawtx,1));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt find enough locked funds"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -611,6 +858,8 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ);
|
||||
CPubKey Paymentspk,mypk,txidpk; uint256 txid,hashBlock; int64_t amount,totalallocations; CScript opret; CTransaction tx; char txidaddr[64]; std::string rawtx; int32_t n,useopret = 0,lockedblocks,minrelease; std::vector<uint256> txidoprets;
|
||||
int32_t top,bottom; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
|
||||
uint256 tokenid; int8_t fixedAmount;
|
||||
cJSON *params = payments_reparse(&n,jsonstr);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
Paymentspk = GetUnspendable(cp,0);
|
||||
@@ -620,14 +869,14 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
|
||||
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049;
|
||||
if ( n == 3 )
|
||||
useopret = jint(jitem(params,2),0) != 0;
|
||||
if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 )
|
||||
if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 && DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 0) )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid createtxid"));
|
||||
}
|
||||
else if ( AddNormalinputs(mtx,mypk,amount+PAYMENTS_TXFEE,60) > 0 )
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
|
||||
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","negative parameter"));
|
||||
@@ -642,18 +891,18 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
|
||||
}
|
||||
else
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk));
|
||||
opret = EncodePaymentsFundOpRet(txid);
|
||||
fprintf(stderr, "opret.%s\n", HexStr(opret.begin(), opret.end()).c_str());
|
||||
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
|
||||
// Use the below one along with other FinalizeCCTx/return, to get the ccvout scriptpubkey
|
||||
/*std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
|
||||
if ( makeCCopret(opret, vData) )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData));
|
||||
fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vData.size(), HexStr(vData[0].begin(),vData[0].end()).c_str());
|
||||
}
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); */
|
||||
}
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript());
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret);
|
||||
//rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); // use this one to get ccvout scriptpubkey.
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
//return(payments_rawtxresult(result,rawtx,0)); // disable sending for CCvout, as we only need to decode the tx.
|
||||
return(payments_rawtxresult(result,rawtx,1));
|
||||
}
|
||||
else
|
||||
@@ -789,63 +1038,58 @@ UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr)
|
||||
|
||||
UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr)
|
||||
{
|
||||
// need to code: exclude list of tokenid, dust threshold, maxpayees, excluded pubkeys[]
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
UniValue result(UniValue::VOBJ); CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::vector<uint256> txidoprets; uint256 hashBlock; int32_t i,n,numoprets=0,lockedblocks,minrelease; std::string rawtx; int64_t totalallocations = 0;
|
||||
UniValue result(UniValue::VOBJ);
|
||||
uint256 hashBlock; CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::string rawtx;
|
||||
int32_t lockedblocks,minrelease,top,bottom,n,i; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t fixedAmount;
|
||||
if ( KOMODO_SNAPSHOT_INTERVAL == 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","cannot use airdrop wihtout -ac_snapshot set."));
|
||||
return(result);
|
||||
}
|
||||
cJSON *params = payments_reparse(&n,jsonstr);
|
||||
if ( params != 0 && n >= 4 )
|
||||
if ( params != 0 && n >= 5 )
|
||||
{
|
||||
lockedblocks = juint(jitem(params,0),0);
|
||||
minrelease = juint(jitem(params,1),0);
|
||||
if ( lockedblocks < 0 || minrelease < 0 )
|
||||
top = juint(jitem(params,2),0);
|
||||
bottom = juint(jitem(params,3),0);
|
||||
fixedAmount = juint(jitem(params,4),0); // fixed amount is a flag set to 0 or 1. It means allocations are equal rather than weighted by address balance.
|
||||
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 || bottom < 0 || fixedAmount < 0 || top > 3999 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","negative parameter"));
|
||||
result.push_back(Pair("error","negative parameter, or top over 3999"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
for (i=0; i<n-2; i++)
|
||||
txidoprets.push_back(payments_juint256(jitem(params,2+i)));
|
||||
for (i=0; i<txidoprets.size(); i++)
|
||||
if ( n > 5 )
|
||||
{
|
||||
std::vector<uint8_t> scriptPubKey,opret; int64_t allocation;
|
||||
if ( myGetTransaction(txidoprets[i],tx,hashBlock) != 0 && tx.vout.size() > 1 && DecodePaymentsTxidOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
|
||||
for (i=0; i<n-5; i++)
|
||||
{
|
||||
totalallocations += allocation;
|
||||
if ( opret.size() > 0 )
|
||||
numoprets++;
|
||||
/* TODO: Change this RPC to take an address. Because a tokens airdrop needs its own RPC anyway.
|
||||
CTxDestination destination = DecodeDestination(name_);
|
||||
CScript scriptPubKey = GetScriptForDestination(destination);
|
||||
*/
|
||||
char *inputhex = jstri(params,3+i);
|
||||
std::vector<uint8_t> scriptPubKey;
|
||||
int32_t len = strlen(inputhex)/2;
|
||||
scriptPubKey.resize(len);
|
||||
decode_hex((uint8_t *)scriptPubKey.data(),len,(char *)inputhex);
|
||||
excludeScriptPubKeys.push_back(scriptPubKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid txidopret"));
|
||||
result.push_back(Pair("txid",txidoprets[i].GetHex()));
|
||||
result.push_back(Pair("txi",(int64_t)i));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
if ( numoprets > 1 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","too many opreturns"));
|
||||
result.push_back(Pair("numoprets",(int64_t)numoprets));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
Paymentspk = GetUnspendable(cp,0);
|
||||
if ( AddNormalinputs(mtx,mypk,2*PAYMENTS_TXFEE,60) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,PAYMENTS_TXFEE,Paymentspk,Paymentspk));
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsOpRet(lockedblocks,minrelease,totalallocations,txidoprets));
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsSnapsShotOpRet(lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(payments_rawtxresult(result,rawtx,1));
|
||||
}
|
||||
}
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","not enough normal funds"));
|
||||
}
|
||||
@@ -862,14 +1106,16 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr)
|
||||
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,txO; CPubKey Paymentspk,txidpk; int32_t i,j,n,flag=0,numoprets=0,lockedblocks,minrelease; std::vector<uint256> txidoprets; int64_t funds,fundsopret,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock;
|
||||
int32_t top,bottom; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
|
||||
uint256 tokenid; int8_t fixedAmount;
|
||||
cJSON *params = payments_reparse(&n,jsonstr);
|
||||
if ( params != 0 && n == 1 )
|
||||
{
|
||||
Paymentspk = GetUnspendable(cp,0);
|
||||
createtxid = payments_juint256(jitem(params,0));
|
||||
if ( myGetTransaction(createtxid,tx,hashBlock) != 0 )
|
||||
if ( myGetTransaction(createtxid,tx,hashBlock) != 0 && tx.vout.size() > 0 )
|
||||
{
|
||||
if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 )
|
||||
if ( DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 )
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
|
||||
{
|
||||
@@ -879,6 +1125,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
result.push_back(Pair("plan_type","payments"));
|
||||
result.push_back(Pair("lockedblocks",(int64_t)lockedblocks));
|
||||
result.push_back(Pair("totalallocations",(int64_t)totalallocations));
|
||||
result.push_back(Pair("minrelease",(int64_t)minrelease));
|
||||
@@ -907,29 +1154,75 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
|
||||
} else fprintf(stderr,"error decoding voutsize.%d\n",(int32_t)txO.vout.size());
|
||||
a.push_back(obj);
|
||||
}
|
||||
flag++;
|
||||
result.push_back(Pair("numoprets",(int64_t)numoprets));
|
||||
if ( numoprets > 1 )
|
||||
{
|
||||
flag++;
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","too many opreturns"));
|
||||
}
|
||||
else
|
||||
} else result.push_back(Pair("txidoprets",a));
|
||||
}
|
||||
else if ( DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys) != 0 )
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 || bottom < 0 || fixedAmount < 0 || top > 3999 )
|
||||
{
|
||||
result.push_back(Pair("txidoprets",a));
|
||||
txidpk = CCtxidaddr(txidaddr,createtxid);
|
||||
GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk);
|
||||
funds = CCaddress_balance(fundsaddr,1);
|
||||
result.push_back(Pair(fundsaddr,ValueFromAmount(funds)));
|
||||
GetCCaddress(cp,fundsopretaddr,Paymentspk);
|
||||
fundsopret = CCaddress_balance(fundsopretaddr,1); // Shows balance for ALL payments plans, not just the one asked for!
|
||||
result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret)));
|
||||
result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret)));
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","negative parameter"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
result.push_back(Pair("plan_type","snapshot"));
|
||||
result.push_back(Pair("lockedblocks",(int64_t)lockedblocks));
|
||||
result.push_back(Pair("minrelease",(int64_t)minrelease));
|
||||
result.push_back(Pair("top",(int64_t)top));
|
||||
result.push_back(Pair("bottom",(int64_t)bottom));
|
||||
result.push_back(Pair("fixedFlag",(int64_t)fixedAmount));
|
||||
// TODO: convert to show addresses instead of scriptpubkey.
|
||||
for ( auto scriptPubKey : excludeScriptPubKeys )
|
||||
a.push_back(HexStr(scriptPubKey.begin(),scriptPubKey.end()));
|
||||
result.push_back(Pair("excludeScriptPubkeys",a));
|
||||
}
|
||||
else if ( DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) != 0 )
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","negative parameter"));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(result);
|
||||
}
|
||||
result.push_back(Pair("plan_type","token snapshot"));
|
||||
result.push_back(Pair("lockedblocks",(int64_t)lockedblocks));
|
||||
result.push_back(Pair("minrelease",(int64_t)minrelease));
|
||||
result.push_back(Pair("top",(int64_t)top));
|
||||
result.push_back(Pair("tokenid",tokenid.ToString()));
|
||||
// TODO: show pubkeys instead of scriptpubkeys
|
||||
for ( auto scriptPubKey : excludeScriptPubKeys )
|
||||
a.push_back(HexStr(scriptPubKey.begin(),scriptPubKey.end()));
|
||||
result.push_back(Pair("excludeScriptPubkeys",a));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt decode valid payments create txid opreturn"));
|
||||
}
|
||||
if ( flag == 0 )
|
||||
{
|
||||
txidpk = CCtxidaddr(txidaddr,createtxid);
|
||||
GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk);
|
||||
funds = CCaddress_balance(fundsaddr,1);
|
||||
result.push_back(Pair(fundsaddr,ValueFromAmount(funds)));
|
||||
GetCCaddress(cp,fundsopretaddr,Paymentspk);
|
||||
// TODO: Shows balance for ALL payments plans, not just the one asked for! Needs to be reworked.
|
||||
fundsopret = CCaddress_balance(fundsopretaddr,1);
|
||||
result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret)));
|
||||
result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret)));
|
||||
result.push_back(Pair("result","success"));
|
||||
}
|
||||
}
|
||||
if ( flag == 0 )
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","couldnt find valid payments create txid"));
|
||||
@@ -947,8 +1240,9 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
|
||||
|
||||
UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr)
|
||||
{
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; uint256 txid,hashBlock;
|
||||
UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease; std::vector<uint256> txidoprets; int64_t totalallocations;
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; uint256 txid,hashBlock,tokenid;
|
||||
UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease; std::vector<uint256> txidoprets; int64_t totalallocations=0;
|
||||
int32_t top=0,bottom=0; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t fixedAmount = 0;
|
||||
Paymentspk = GetUnspendable(cp,0);
|
||||
GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk);
|
||||
SetCCtxids(addressIndex,markeraddr,true);
|
||||
@@ -957,9 +1251,9 @@ UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr)
|
||||
txid = it->first.txhash;
|
||||
if ( it->first.index == 0 && myGetTransaction(txid,tx,hashBlock) != 0 )
|
||||
{
|
||||
if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 'C' )
|
||||
if ( tx.vout.size() > 0 && (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 'C' || DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys) == 'S' || DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 'O') )
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
|
||||
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) || bottom < 0 || fixedAmount < 0 )
|
||||
{
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","negative parameter"));
|
||||
@@ -970,6 +1264,6 @@ UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr)
|
||||
}
|
||||
}
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("createtxids",a));
|
||||
return(result);
|
||||
result.push_back(Pair("createtxids",a));
|
||||
return(result);
|
||||
}
|
||||
|
||||
13
src/init.cpp
13
src/init.cpp
@@ -35,6 +35,7 @@
|
||||
#include "httprpc.h"
|
||||
#include "key.h"
|
||||
#include "notarisationdb.h"
|
||||
|
||||
#ifdef ENABLE_MINING
|
||||
#include "key_io.h"
|
||||
#endif
|
||||
@@ -55,6 +56,7 @@
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet/wallet.h"
|
||||
#include "wallet/walletdb.h"
|
||||
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -89,9 +91,11 @@
|
||||
using namespace std;
|
||||
|
||||
extern void ThreadSendAlert();
|
||||
extern bool komodo_dailysnapshot(int32_t height);
|
||||
extern int32_t KOMODO_LOADINGBLOCKS;
|
||||
extern bool VERUS_MINTBLOCKS;
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
extern int32_t KOMODO_SNAPSHOT_INTERVAL;
|
||||
|
||||
ZCJoinSplit* pzcashParams = NULL;
|
||||
|
||||
@@ -1622,6 +1626,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ASSETCHAINS_CC != 0 && KOMODO_SNAPSHOT_INTERVAL != 0 && chainActive.Height() >= KOMODO_SNAPSHOT_INTERVAL )
|
||||
{
|
||||
if ( !komodo_dailysnapshot(chainActive.Height()) )
|
||||
{
|
||||
strLoadError = _("daily snapshot failed, please reindex your chain.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fReindex) {
|
||||
uiInterface.InitMessage(_("Rewinding blocks if needed..."));
|
||||
|
||||
@@ -2045,9 +2045,40 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height)
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool komodo_appendACscriptpub()
|
||||
{
|
||||
static bool didinit = false;
|
||||
if ( didinit )
|
||||
return didinit;
|
||||
if ( ASSETCHAINS_SCRIPTPUB[ASSETCHAINS_SCRIPTPUB.back()] == 49 && ASSETCHAINS_SCRIPTPUB[ASSETCHAINS_SCRIPTPUB.back()-1] == 51 )
|
||||
{
|
||||
CTransaction tx; uint256 blockhash;
|
||||
// get transaction and check that it occured before height 100.
|
||||
if ( myGetTransaction(KOMODO_EARLYTXID,tx,blockhash) && mapBlockIndex[blockhash]->GetHeight() < 100 )
|
||||
{
|
||||
for (int i = 0; i < tx.vout.size(); i++)
|
||||
{
|
||||
if ( tx.vout[i].scriptPubKey[0] == OP_RETURN )
|
||||
{
|
||||
ASSETCHAINS_SCRIPTPUB.pop_back(); ASSETCHAINS_SCRIPTPUB.pop_back(); // remove last 2 chars.
|
||||
// get OP_RETURN from txid and append the HexStr of it to scriptpub
|
||||
// encoded opreturn incorrectly on TESTHC chain, once we no longer need this it can be changed to a straight +1 to drop OP_RETURN opcode.
|
||||
ASSETCHAINS_SCRIPTPUB.append(HexStr(tx.vout[i].scriptPubKey.begin()+3, tx.vout[i].scriptPubKey.end()));
|
||||
//fprintf(stderr, "ac_script.%s\n",ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
didinit = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "could not get KOMODO_EARLYTXID.%s OP_RETURN data. Restart with correct txid!\n", KOMODO_EARLYTXID.GetHex().c_str());
|
||||
StartShutdown();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
|
||||
{
|
||||
int64_t checktoshis=0; uint8_t *script,scripthex[8192]; int32_t scriptlen,matched = 0;
|
||||
int64_t checktoshis=0; uint8_t *script,scripthex[8192]; int32_t scriptlen,matched = 0; static bool didinit = false;
|
||||
if ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 )
|
||||
{
|
||||
checktoshis = komodo_commission(pblock,height);
|
||||
@@ -2069,6 +2100,12 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
|
||||
}
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
|
||||
{
|
||||
static bool didinit = false;
|
||||
if ( !didinit && height > 100 && KOMODO_EARLYTXID != zeroid && komodo_appendACscriptpub() )
|
||||
{
|
||||
fprintf(stderr, "appended CC_op_return to ASSETCHAINS_SCRIPTPUB.%s\n", ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
didinit = true;
|
||||
}
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size()/2 == scriptlen && scriptlen < sizeof(scripthex) )
|
||||
{
|
||||
decode_hex(scripthex,scriptlen,(char *)ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
@@ -2205,11 +2242,11 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
else if ( ASSETCHAINS_STAKED != 0 )
|
||||
failed = 0;
|
||||
}
|
||||
if ( failed == 0 && ASSETCHAINS_COMMISSION != 0 ) //ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
|
||||
if ( failed == 0 && ASSETCHAINS_COMMISSION != 0 )
|
||||
{
|
||||
if ( height == 1 )
|
||||
{
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 && ASSETCHAINS_SCRIPTPUB[ASSETCHAINS_SCRIPTPUB.back()] != 49 && ASSETCHAINS_SCRIPTPUB[ASSETCHAINS_SCRIPTPUB.back()-1] != 51 )
|
||||
{
|
||||
int32_t scriptlen; uint8_t scripthex[10000];
|
||||
script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
|
||||
@@ -2221,7 +2258,7 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
return(-1);
|
||||
} else return(-1);
|
||||
}
|
||||
else
|
||||
else if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
|
||||
{
|
||||
script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
|
||||
scriptlen = (int32_t)pblock->vtx[0].vout[0].scriptPubKey.size();
|
||||
|
||||
@@ -63,7 +63,7 @@ extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS
|
||||
extern std::vector<std::string> ASSETCHAINS_PRICES,ASSETCHAINS_STOCKS;
|
||||
|
||||
extern int32_t VERUS_BLOCK_POSUNITS, VERUS_CONSECUTIVE_POS_THRESHOLD, VERUS_NOPOS_THRESHHOLD;
|
||||
|
||||
extern uint256 KOMODO_EARLYTXID;
|
||||
|
||||
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE,KOMODO_DEALERNODE;
|
||||
extern uint32_t ASSETCHAINS_CC;
|
||||
@@ -78,7 +78,7 @@ extern std::string DONATION_PUBKEY;
|
||||
extern uint8_t ASSETCHAINS_PRIVATE;
|
||||
extern int32_t USE_EXTERNAL_PUBKEY;
|
||||
extern char NOTARYADDRS[64][64];
|
||||
extern int32_t KOMODO_TESTNODE;
|
||||
extern int32_t KOMODO_TESTNODE, KOMODO_SNAPSHOT_INTERVAL;
|
||||
int tx_height( const uint256 &hash );
|
||||
extern std::vector<std::string> vWhiteListAddress;
|
||||
void komodo_netevent(std::vector<uint8_t> payload);
|
||||
|
||||
@@ -109,7 +109,7 @@ uint64_t PENDING_KOMODO_TX;
|
||||
extern int32_t KOMODO_LOADINGBLOCKS;
|
||||
unsigned int MAX_BLOCK_SIGOPS = 20000;
|
||||
|
||||
int32_t KOMODO_TESTNODE;
|
||||
int32_t KOMODO_TESTNODE, KOMODO_SNAPSHOT_INTERVAL;
|
||||
|
||||
struct komodo_kv *KOMODO_KV;
|
||||
pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex;
|
||||
|
||||
@@ -1752,6 +1752,7 @@ void komodo_args(char *argv0)
|
||||
ASSETCHAINS_BLOCKTIME = GetArg("-ac_blocktime",60);
|
||||
ASSETCHAINS_PUBLIC = GetArg("-ac_public",0);
|
||||
ASSETCHAINS_PRIVATE = GetArg("-ac_private",0);
|
||||
KOMODO_SNAPSHOT_INTERVAL = GetArg("-ac_snapshot",0);
|
||||
Split(GetArg("-ac_nk",""), ASSETCHAINS_NK, 0);
|
||||
if ( (KOMODO_REWIND= GetArg("-rewind",0)) != 0 )
|
||||
{
|
||||
@@ -2012,7 +2013,7 @@ void komodo_args(char *argv0)
|
||||
fprintf(stderr,"-ac_script and -ac_marmara are mutually exclusive\n");
|
||||
StartShutdown();
|
||||
}
|
||||
if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 || ASSETCHAINS_CBOPRET != 0 || Mineropret.size() != 0 || (ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0) )
|
||||
if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 || ASSETCHAINS_CBOPRET != 0 || Mineropret.size() != 0 || (ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0) || KOMODO_SNAPSHOT_INTERVAL != 0 )
|
||||
{
|
||||
fprintf(stderr,"perc %.4f%% ac_pub=[%02x%02x%02x...] acsize.%d\n",dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0],ASSETCHAINS_OVERRIDE_PUBKEY33[1],ASSETCHAINS_OVERRIDE_PUBKEY33[2],(int32_t)ASSETCHAINS_SCRIPTPUB.size());
|
||||
extraptr = extrabuf;
|
||||
@@ -2072,6 +2073,7 @@ void komodo_args(char *argv0)
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_FOUNDERS),(void *)&ASSETCHAINS_FOUNDERS);
|
||||
if ( ASSETCHAINS_FOUNDERS_REWARD != 0 )
|
||||
{
|
||||
fprintf(stderr, "set founders reward.%li\n",ASSETCHAINS_FOUNDERS_REWARD);
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_FOUNDERS_REWARD),(void *)&ASSETCHAINS_FOUNDERS_REWARD);
|
||||
}
|
||||
}
|
||||
@@ -2147,6 +2149,11 @@ void komodo_args(char *argv0)
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_NK[0]),(void *)&ASSETCHAINS_NK[0]);
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_NK[1]),(void *)&ASSETCHAINS_NK[1]);
|
||||
}
|
||||
if ( KOMODO_SNAPSHOT_INTERVAL != 0 )
|
||||
{
|
||||
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(KOMODO_SNAPSHOT_INTERVAL),(void *)&KOMODO_SNAPSHOT_INTERVAL);
|
||||
fprintf(stderr, "snapshot interval.%i\n",KOMODO_SNAPSHOT_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
addn = GetArg("-seednode","");
|
||||
|
||||
110
src/main.cpp
110
src/main.cpp
@@ -642,6 +642,102 @@ UniValue komodo_snapshot(int top)
|
||||
return(result);
|
||||
}
|
||||
|
||||
bool komodo_snapshot2(std::map <std::string, CAmount> &addressAmounts)
|
||||
{
|
||||
if ( fAddressIndex && pblocktree != 0 )
|
||||
{
|
||||
return pblocktree->Snapshot2(addressAmounts, 0);
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
int32_t lastSnapShotHeight = 0;
|
||||
std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot;
|
||||
|
||||
bool komodo_dailysnapshot(int32_t height)
|
||||
{
|
||||
int reorglimit = 10; // CHANGE BACK TO 100 AFTER TESTING!
|
||||
uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,undo_height,extraoffset;
|
||||
if ( (extraoffset= height % KOMODO_SNAPSHOT_INTERVAL) != 0 )
|
||||
{
|
||||
// we are on chain init, and need to scan all the way back to the correct height, other wise our node will have a diffrent snapshot to online nodes.
|
||||
// use the notarizationsDB to scan back from the consesnus height to get the offset we need.
|
||||
std::string symbol; Notarisation nota;
|
||||
symbol.assign(ASSETCHAINS_SYMBOL);
|
||||
if ( ScanNotarisationsDB(height-extraoffset, symbol, 100, nota) == 0 )
|
||||
undo_height = height-extraoffset-reorglimit;
|
||||
else undo_height = nota.second.height;
|
||||
//fprintf(stderr, "height.%i-extraoffset.%i = startscanfrom.%i to get undo_height.%i\n", height, extraoffset, height-extraoffset, undo_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are at the right height in connect block to scan back to last notarized height.
|
||||
notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid);
|
||||
notarized_height > height-reorglimit ? undo_height = notarized_height : undo_height = height-reorglimit;
|
||||
}
|
||||
fprintf(stderr, "doing snapshot for height.%i undo_height.%i\n", height, undo_height);
|
||||
// if we already did this height dont bother doing it again, this is just a reorg. The actual snapshot height cannot be reorged.
|
||||
if ( undo_height == lastSnapShotHeight )
|
||||
return true;
|
||||
std::map <std::string, int64_t> addressAmounts;
|
||||
if ( !komodo_snapshot2(addressAmounts) )
|
||||
return false;
|
||||
|
||||
// undo blocks in reverse order
|
||||
for (int32_t n = height; n > undo_height; n--)
|
||||
{
|
||||
//fprintf(stderr, "undoing block.%i\n",n);
|
||||
CBlockIndex *pindex; CBlock block;
|
||||
if ( (pindex= komodo_chainactive(n)) == 0 || komodo_blockload(block, pindex) != 0 )
|
||||
return false;
|
||||
// undo transactions in reverse order
|
||||
for (int32_t i = block.vtx.size() - 1; i >= 0; i--)
|
||||
{
|
||||
const CTransaction &tx = block.vtx[i];
|
||||
CTxDestination vDest;
|
||||
// loop vouts reverse order, remove value recieved.
|
||||
for (unsigned int k = tx.vout.size(); k-- > 0;)
|
||||
{
|
||||
const CTxOut &out = tx.vout[k];
|
||||
if ( ExtractDestination(out.scriptPubKey, vDest) )
|
||||
{
|
||||
addressAmounts[CBitcoinAddress(vDest).ToString()] -= out.nValue;
|
||||
if ( addressAmounts[CBitcoinAddress(vDest).ToString()] < 1 )
|
||||
addressAmounts.erase(CBitcoinAddress(vDest).ToString());
|
||||
//fprintf(stderr, "VOUT: address.%s remove_coins.%li\n",CBitcoinAddress(vDest).ToString().c_str(), out.nValue);
|
||||
}
|
||||
}
|
||||
// loop vins in reverse order, get prevout and return the sent balance.
|
||||
for (unsigned int j = tx.vin.size(); j-- > 0;)
|
||||
{
|
||||
uint256 blockhash; CTransaction txin;
|
||||
if ( !tx.IsCoinImport() && !tx.IsCoinBase() && myGetTransaction(tx.vin[j].prevout.hash,txin,blockhash) )
|
||||
{
|
||||
int vout = tx.vin[j].prevout.n;
|
||||
if ( ExtractDestination(txin.vout[vout].scriptPubKey, vDest) )
|
||||
{
|
||||
//fprintf(stderr, "VIN: address.%s add_coins.%li\n",CBitcoinAddress(vDest).ToString().c_str(), txin.vout[vout].nValue);
|
||||
addressAmounts[CBitcoinAddress(vDest).ToString()] += txin.vout[vout].nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vAddressSnapshot.clear(); // clear existing snapshot
|
||||
// convert address string to destination for easier conversion to what ever is required, eg, scriptPubKey.
|
||||
for ( auto element : addressAmounts)
|
||||
vAddressSnapshot.push_back(make_pair(element.second, DecodeDestination(element.first)));
|
||||
// sort the vector by amount, highest at top.
|
||||
std::sort(vAddressSnapshot.rbegin(), vAddressSnapshot.rend());
|
||||
//for (int j = 0; j < 50; j++)
|
||||
// fprintf(stderr, "j.%i address.%s nValue.%li\n",j, CBitcoinAddress(vAddressSnapshot[j].second).ToString().c_str(), vAddressSnapshot[j].first );
|
||||
// include only top 5000 address.
|
||||
if ( vAddressSnapshot.size() > 3999 ) vAddressSnapshot.resize(3999);
|
||||
lastSnapShotHeight = undo_height;
|
||||
fprintf(stderr, "vAddressSnapshot.size.%li\n", vAddressSnapshot.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// mapOrphanTransactions
|
||||
@@ -3096,7 +3192,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
uint160 addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr);
|
||||
// undo spending activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(keyType, addrHash, pindex->GetHeight(), i, hash, j, true), prevout.nValue * -1));
|
||||
|
||||
// restore unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(keyType, addrHash, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight)));
|
||||
}
|
||||
@@ -3497,8 +3592,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
fprintf(stderr,"valueout %.8f too big\n",(double)valueout/COIN);
|
||||
return state.DoS(100, error("ConnectBlock(): GetValueOut too big"),REJECT_INVALID,"tx valueout is too big");
|
||||
}
|
||||
prevsum = voutsum;
|
||||
voutsum += valueout;
|
||||
//prevsum = voutsum;
|
||||
//voutsum += valueout;
|
||||
/*if ( KOMODO_VALUETOOBIG(voutsum) != 0 )
|
||||
{
|
||||
fprintf(stderr,"voutsum %.8f too big\n",(double)voutsum/COIN);
|
||||
@@ -4163,6 +4258,13 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
||||
komodo_pricesupdate(pindexNew->GetHeight(),pblock);
|
||||
if ( ASSETCHAINS_SAPLING <= 0 && pindexNew->nTime > KOMODO_SAPLING_ACTIVATION - 24*3600 )
|
||||
komodo_activate_sapling(pindexNew);
|
||||
if ( ASSETCHAINS_CC != 0 && KOMODO_SNAPSHOT_INTERVAL != 0 && (pindexNew->GetHeight() % KOMODO_SNAPSHOT_INTERVAL) == 0 && pindexNew->GetHeight() >= KOMODO_SNAPSHOT_INTERVAL )
|
||||
{
|
||||
uint64_t start = time(NULL);
|
||||
if ( !komodo_dailysnapshot(pindexNew->GetHeight()) )
|
||||
fprintf(stderr, "daily snapshot failed, please reindex your chain\n"); // maybe force shutdown here?
|
||||
fprintf(stderr, "snapshot completed in: %lu seconds\n", time(NULL)-start);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6102,7 +6204,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
|
||||
}
|
||||
|
||||
LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->GetHeight(), nGoodTransactions);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ uint64_t komodo_notarypay(CMutableTransaction &txNew, std::vector<int8_t> &Notar
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
int32_t komodo_getnotarizedheight(uint32_t timestamp,int32_t height, uint8_t *script, int32_t len);
|
||||
CScript komodo_mineropret(int32_t nHeight);
|
||||
bool komodo_appendACscriptpub();
|
||||
|
||||
CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake)
|
||||
{
|
||||
@@ -290,9 +291,9 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
txvalue = tx.GetValueOut();
|
||||
if ( KOMODO_VALUETOOBIG(txvalue) != 0 )
|
||||
continue;
|
||||
if ( KOMODO_VALUETOOBIG(txvalue + voutsum) != 0 )
|
||||
continue;
|
||||
voutsum += txvalue;
|
||||
//if ( KOMODO_VALUETOOBIG(txvalue + voutsum) != 0 ) // has been commented from main.cpp ?
|
||||
// continue;
|
||||
//voutsum += txvalue;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 )
|
||||
{
|
||||
//fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime);
|
||||
@@ -652,6 +653,12 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
txNew.vout[1].nValue = commission;
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
|
||||
{
|
||||
static bool didinit = false;
|
||||
if ( !didinit && nHeight > 100 && KOMODO_EARLYTXID != zeroid && komodo_appendACscriptpub() )
|
||||
{
|
||||
fprintf(stderr, "appended ccopreturn to ASSETCHAINS_SCRIPTPUB.%s\n", ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
didinit = true;
|
||||
}
|
||||
//fprintf(stderr,"mine to -ac_script\n");
|
||||
//txNew.vout[1].scriptPubKey = CScript() << ParseHex();
|
||||
int32_t len = strlen(ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
@@ -895,14 +902,14 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
|
||||
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, int32_t gpucount, bool isStake)
|
||||
{
|
||||
CPubKey pubkey; CScript scriptPubKey; uint8_t *script,*ptr; int32_t i,len;
|
||||
if ( nHeight == 1 && ASSETCHAINS_COMMISSION != 0 )
|
||||
if ( nHeight == 1 && ASSETCHAINS_COMMISSION != 0 && ASSETCHAINS_SCRIPTPUB[ASSETCHAINS_SCRIPTPUB.back()] != 49 && ASSETCHAINS_SCRIPTPUB[ASSETCHAINS_SCRIPTPUB.back()-1] != 51 )
|
||||
{
|
||||
if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
|
||||
{
|
||||
pubkey = ParseHex(ASSETCHAINS_OVERRIDE_PUBKEY);
|
||||
scriptPubKey = CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
len = strlen(ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
len >>= 1;
|
||||
|
||||
@@ -480,12 +480,13 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "marmara", "marmaralock", &marmara_lock, true },
|
||||
|
||||
// Payments
|
||||
{ "payments", "paymentsaddress", &paymentsaddress, true },
|
||||
{ "payments", "paymentstxidopret", &payments_txidopret, true },
|
||||
{ "payments", "paymentscreate", &payments_create, true },
|
||||
{ "payments", "paymentslist", &payments_list, true },
|
||||
{ "payments", "paymentsinfo", &payments_info, true },
|
||||
{ "payments", "paymentsfund", &payments_fund, true },
|
||||
{ "payments", "paymentsaddress", &paymentsaddress, true },
|
||||
{ "payments", "paymentstxidopret", &payments_txidopret, true },
|
||||
{ "payments", "paymentscreate", &payments_create, true },
|
||||
{ "payments", "paymentsairdrop", &payments_airdrop, true },
|
||||
{ "payments", "paymentslist", &payments_list, true },
|
||||
{ "payments", "paymentsinfo", &payments_info, true },
|
||||
{ "payments", "paymentsfund", &payments_fund, true },
|
||||
{ "payments", "paymentsrelease", &payments_release, true },
|
||||
|
||||
{ "CClib", "cclibaddress", &cclibaddress, true },
|
||||
@@ -641,6 +642,7 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "wallet", "z_importviewingkey", &z_importviewingkey, true },
|
||||
{ "wallet", "z_exportwallet", &z_exportwallet, true },
|
||||
{ "wallet", "z_importwallet", &z_importwallet, true },
|
||||
{ "wallet", "opreturn_burn", &opreturn_burn, true },
|
||||
|
||||
// TODO: rearrange into another category
|
||||
{ "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true },
|
||||
|
||||
@@ -289,6 +289,7 @@ extern UniValue payments_release(const UniValue& params, bool fHelp);
|
||||
extern UniValue payments_fund(const UniValue& params, bool fHelp);
|
||||
extern UniValue payments_txidopret(const UniValue& params, bool fHelp);
|
||||
extern UniValue payments_create(const UniValue& params, bool fHelp);
|
||||
extern UniValue payments_airdrop(const UniValue& params, bool fHelp);
|
||||
extern UniValue payments_info(const UniValue& params, bool fHelp);
|
||||
extern UniValue payments_list(const UniValue& params, bool fHelp);
|
||||
|
||||
@@ -468,6 +469,7 @@ extern UniValue z_shieldcoinbase(const UniValue& params, bool fHelp); // in rpcw
|
||||
extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern UniValue z_getoperationresult(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern UniValue z_listoperationids(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern UniValue opreturn_burn(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||
extern UniValue z_validateaddress(const UniValue& params, bool fHelp); // in rpcmisc.cpp
|
||||
extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp
|
||||
extern UniValue z_validatepaymentdisclosure(const UniValue ¶ms, bool fHelp); // in rpcdisclosure.cpp
|
||||
|
||||
89
src/txdb.cpp
89
src/txdb.cpp
@@ -458,13 +458,13 @@ uint32_t komodo_segid32(char *coinaddr);
|
||||
{"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} \
|
||||
};
|
||||
|
||||
int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector <std::pair<CAmount, std::string>> &vaddr, UniValue *ret)
|
||||
bool CBlockTreeDB::Snapshot2(std::map <std::string, CAmount> &addressAmounts, UniValue *ret)
|
||||
{
|
||||
int64_t total = 0; int64_t totalAddresses = 0; std::string address;
|
||||
int64_t utxos = 0; int64_t ignoredAddresses = 0, cryptoConditionsUTXOs = 0, cryptoConditionsTotals = 0;
|
||||
DECLARE_IGNORELIST
|
||||
boost::scoped_ptr<CDBIterator> iter(NewIterator());
|
||||
std::map <std::string, CAmount> addressAmounts;
|
||||
//std::map <std::string, CAmount> addressAmounts;
|
||||
for (iter->SeekToLast(); iter->Valid(); iter->Prev())
|
||||
{
|
||||
boost::this_thread::interruption_point();
|
||||
@@ -486,40 +486,39 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector
|
||||
{
|
||||
cryptoConditionsUTXOs++;
|
||||
cryptoConditionsTotals += nValue;
|
||||
total += nValue;
|
||||
continue;
|
||||
}
|
||||
if ( nValue > dustthreshold )
|
||||
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
|
||||
if (ignored != ignoredMap.end())
|
||||
{
|
||||
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
|
||||
if (ignored != ignoredMap.end())
|
||||
{
|
||||
fprintf(stderr,"ignoring %s\n", address.c_str());
|
||||
ignoredAddresses++;
|
||||
continue;
|
||||
}
|
||||
std::map <std::string, CAmount>::iterator pos = addressAmounts.find(address);
|
||||
if ( pos == addressAmounts.end() )
|
||||
{
|
||||
// insert new address + utxo amount
|
||||
//fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] = nValue;
|
||||
totalAddresses++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update unspent tally for this address
|
||||
//fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] += nValue;
|
||||
}
|
||||
//fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
|
||||
// total += nValue;
|
||||
utxos++;
|
||||
} //else fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str());
|
||||
fprintf(stderr,"ignoring %s\n", address.c_str());
|
||||
ignoredAddresses++;
|
||||
continue;
|
||||
}
|
||||
std::map <std::string, CAmount>::iterator pos = addressAmounts.find(address);
|
||||
if ( pos == addressAmounts.end() )
|
||||
{
|
||||
// insert new address + utxo amount
|
||||
//fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] = nValue;
|
||||
totalAddresses++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update unspent tally for this address
|
||||
//fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] += nValue;
|
||||
}
|
||||
//fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
|
||||
// total += nValue;
|
||||
utxos++;
|
||||
total += nValue;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
fprintf(stderr, "DONE %s: LevelDB addressindex exception! - %s\n", __func__, e.what());
|
||||
break;
|
||||
return false; //break; this means failiure of DB? we need to exit here if so for consensus code!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -530,30 +529,18 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector
|
||||
}
|
||||
}
|
||||
//fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses);
|
||||
for (std::pair<std::string, CAmount> element : addressAmounts)
|
||||
vaddr.push_back( make_pair(element.second, element.first) );
|
||||
std::sort(vaddr.rbegin(), vaddr.rend());
|
||||
int topN = 0;
|
||||
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it)
|
||||
{
|
||||
total += it->first;
|
||||
topN++;
|
||||
// If requested, only show top N addresses in output JSON
|
||||
if ( top == topN )
|
||||
break;
|
||||
}
|
||||
|
||||
// this is for the snapshot RPC, you can skip this by passing a 0 as the last argument.
|
||||
if (ret)
|
||||
{
|
||||
// Total amount in this snapshot, which is less than circulating supply if top parameter is used
|
||||
// Use the address_total for a total of all address included when using top parameter.
|
||||
ret->push_back(make_pair("total", (double) (total+cryptoConditionsTotals)/ COIN ));
|
||||
// Total circulating supply without CC vouts.
|
||||
ret->push_back(make_pair("total", (double) (total)/ COIN ));
|
||||
// Average amount in each address of this snapshot
|
||||
ret->push_back(make_pair("average",(double) (total/COIN) / totalAddresses ));
|
||||
// Total number of utxos processed in this snaphot
|
||||
ret->push_back(make_pair("utxos", utxos));
|
||||
// Total number of addresses in this snaphot
|
||||
ret->push_back(make_pair("total_addresses", top ? top : totalAddresses ));
|
||||
ret->push_back(make_pair("total_addresses", totalAddresses ));
|
||||
// Total number of ignored addresses in this snaphot
|
||||
ret->push_back(make_pair("ignored_addresses", ignoredAddresses));
|
||||
// Total number of crypto condition utxos we skipped
|
||||
@@ -561,22 +548,28 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top ,std::vector
|
||||
// Total value of skipped crypto condition utxos
|
||||
ret->push_back(make_pair("cc_utxo_value", (double) cryptoConditionsTotals / COIN));
|
||||
// total of all the address's, does not count coins in CC vouts.
|
||||
ret->push_back(make_pair("address_total", (double) total/ COIN ));
|
||||
ret->push_back(make_pair("total_includeCCvouts", (double) (total+cryptoConditionsTotals)/ COIN ));
|
||||
// The snapshot finished at this block height
|
||||
ret->push_back(make_pair("ending_height", chainActive.Height()));
|
||||
}
|
||||
return(topN);
|
||||
return true;
|
||||
}
|
||||
|
||||
UniValue CBlockTreeDB::Snapshot(int top)
|
||||
{
|
||||
int topN = 0;
|
||||
std::vector <std::pair<CAmount, std::string>> vaddr;
|
||||
//std::vector <std::vector <std::pair<CAmount, CScript>>> tokenids;
|
||||
std::map <std::string, CAmount> addressAmounts;
|
||||
UniValue result(UniValue::VOBJ);
|
||||
UniValue addressesSorted(UniValue::VARR);
|
||||
result.push_back(Pair("start_time", (int) time(NULL)));
|
||||
if ( Snapshot2(0,top,vaddr,&result) != 0 )
|
||||
if ( Snapshot2(addressAmounts,&result) )
|
||||
{
|
||||
for (std::pair<std::string, CAmount> element : addressAmounts)
|
||||
vaddr.push_back( make_pair(element.second, element.first) );
|
||||
std::sort(vaddr.rbegin(), vaddr.rend());
|
||||
int topN = 0;
|
||||
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it)
|
||||
{
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
|
||||
@@ -116,7 +116,7 @@ public:
|
||||
bool LoadBlockIndexGuts();
|
||||
bool blockOnchainActive(const uint256 &hash);
|
||||
UniValue Snapshot(int top);
|
||||
int32_t Snapshot2(int64_t dustthreshold, int32_t top,std::vector <std::pair<CAmount, std::string>> &vaddr, UniValue *ret);
|
||||
bool Snapshot2(std::map <std::string, CAmount> &addressAmounts, UniValue *ret);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_TXDB_H
|
||||
|
||||
@@ -5629,6 +5629,19 @@ UniValue payments_create(const UniValue& params, bool fHelp)
|
||||
return(PaymentsCreate(cp,(char *)params[0].get_str().c_str()));
|
||||
}
|
||||
|
||||
UniValue payments_airdrop(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C;
|
||||
if ( fHelp || params.size() != 1 )
|
||||
throw runtime_error("paymentsairdrop \"[lockedblocks,minamount,top,bottom,fixedFlag,%22excludeAddress%22,...,%22excludeAddressN%22]\"\n");
|
||||
if ( ensure_CCrequirements(EVAL_PAYMENTS) < 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);
|
||||
cp = CCinit(&C,EVAL_PAYMENTS);
|
||||
return(PaymentsAirdrop(cp,(char *)params[0].get_str().c_str()));
|
||||
}
|
||||
|
||||
UniValue payments_info(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C;
|
||||
@@ -7980,9 +7993,11 @@ UniValue test_ac(const UniValue& params, bool fHelp)
|
||||
return(FinalizeCCTx(0, cp, mtx, myPubkey, txfee, opret));
|
||||
}
|
||||
|
||||
extern bool komodo_appendACscriptpub();
|
||||
|
||||
UniValue test_heirmarker(const UniValue& params, bool fHelp)
|
||||
{
|
||||
// make fake token tx:
|
||||
//make fake token tx:
|
||||
struct CCcontract_info *cp, C;
|
||||
|
||||
if (fHelp || (params.size() != 1))
|
||||
@@ -8011,6 +8026,45 @@ UniValue test_heirmarker(const UniValue& params, bool fHelp)
|
||||
return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, opret));
|
||||
}
|
||||
|
||||
UniValue opreturn_burn(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || (params.size() != 2))
|
||||
throw runtime_error("amount to burn, hexstring to send\n");
|
||||
struct CCcontract_info *cp, C; UniValue ret(UniValue::VOBJ);
|
||||
if (ensure_CCrequirements(EVAL_PAYMENTS) < 0)
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
cp = CCinit(&C, EVAL_PAYMENTS);
|
||||
|
||||
CAmount nAmount = AmountFromValue(params[0]);
|
||||
if (nAmount <= 10000)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "must send at least 10000 sat");
|
||||
std::string strHex = params[1].get_str();
|
||||
CPubKey myPubkey = pubkey2pk(Mypubkey());
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
|
||||
int64_t normalInputs = AddNormalinputs(mtx, myPubkey, nAmount, 60);
|
||||
if (normalInputs < nAmount)
|
||||
throw runtime_error("not enough normals\n");
|
||||
|
||||
CScript opret; uint8_t scripthex[8192];
|
||||
|
||||
decode_hex(scripthex,strHex.size()/2,(char *)strHex.c_str());
|
||||
std::string test;
|
||||
test.append((char*)scripthex);
|
||||
std::vector<uint8_t> opretdata(test.begin(), test.end());
|
||||
opret << OP_RETURN << E_MARSHAL(ss << opretdata);
|
||||
/*CScript opret; uint8_t *ptr;
|
||||
opret << OP_RETURN << 0;
|
||||
int32_t len = strlen(strHex.c_str());
|
||||
len >>=1;
|
||||
opret.resize(len+2);
|
||||
ptr = (uint8_t *)&opret[1];
|
||||
decode_hex(ptr,len,(char *)strHex.c_str()); */
|
||||
mtx.vout.push_back(CTxOut(nAmount,opret));
|
||||
ret.push_back(Pair("hex",FinalizeCCTx(0, cp, mtx, myPubkey, 10000, CScript())));
|
||||
return(ret);
|
||||
}
|
||||
|
||||
UniValue test_burntx(const UniValue& params, bool fHelp)
|
||||
{
|
||||
// make fake token tx:
|
||||
|
||||
Reference in New Issue
Block a user