Merge branch 'duke' into dev
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -155,3 +155,5 @@ src/rogue.scr
|
||||
|
||||
src/cc/rogue/confdefs.h
|
||||
src/cc/rogue/x64
|
||||
|
||||
src/cc/dapps/a.out
|
||||
|
||||
28147
contrib/snapshot/airdrop_hush3.sh
Executable file
28147
contrib/snapshot/airdrop_hush3.sh
Executable file
File diff suppressed because it is too large
Load Diff
3127
contrib/snapshot/airdrop_txids.txt
Normal file
3127
contrib/snapshot/airdrop_txids.txt
Normal file
File diff suppressed because it is too large
Load Diff
28147
contrib/snapshot/testnet_airdrop_hush3.sh
Executable file
28147
contrib/snapshot/testnet_airdrop_hush3.sh
Executable file
File diff suppressed because it is too large
Load Diff
@@ -491,7 +491,7 @@ libbitcoin_common_a_SOURCES = \
|
||||
script/sign.cpp \
|
||||
script/standard.cpp \
|
||||
transaction_builder.cpp \
|
||||
cc/CCtokensOpRet.cpp \
|
||||
cc/CCtokenutils.cpp \
|
||||
cc/CCutilbits.cpp \
|
||||
$(BITCOIN_CORE_H) \
|
||||
$(LIBZCASH_H)
|
||||
|
||||
2
src/ac/vote2019
Executable file
2
src/ac/vote2019
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=VOTE2019 $1 $2 $3 $4 $5 $6
|
||||
@@ -257,5 +257,11 @@
|
||||
"ac_reward": "100000000",
|
||||
"ac_cc": "3",
|
||||
"addnode": ["138.201.136.145"]
|
||||
},
|
||||
{
|
||||
"ac_name": "VOTE2019",
|
||||
"ac_supply": "123651638",
|
||||
"ac_public": "1",
|
||||
"addnode": ["95.213.238.98"]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -49,3 +49,4 @@ echo $pubkey
|
||||
./komodod -pubkey=$pubkey -ac_name=ILN -ac_supply=10000000000 -ac_cc=2 -addressindex=1 -spentindex=1 -addnode=51.75.122.83 &
|
||||
./komodod -pubkey=$pubkey -ac_name=RICK -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 &
|
||||
./komodod -pubkey=$pubkey -ac_name=MORTY -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 &
|
||||
./komodod -pubkey=$pubkey -ac_name=VOTE2019 -ac_supply=123651638 -ac_public=1 -addnode=95.213.238.98 &
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
bool ImportGatewayValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn);
|
||||
bool ImportGatewayExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
|
||||
std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4);
|
||||
std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t burnvout,std::string rawburntx,std::vector<uint8_t>proof,CPubKey destpub);
|
||||
std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t burnvout,std::string rawburntx,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount);
|
||||
std::string ImportGatewayWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount);
|
||||
std::string ImportGatewayPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex);
|
||||
std::string ImportGatewayCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define CC_PRICES_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,int32_t ind);
|
||||
int32_t komodo_priceget(int64_t *buf64,int32_t ind,int32_t height,int32_t numblocks);
|
||||
|
||||
#define PRICES_DAYWINDOW ((3600*24/ASSETCHAINS_BLOCKTIME) + 1)
|
||||
#define PRICES_TXFEE 10000
|
||||
|
||||
@@ -164,6 +164,7 @@ UniValue CClib_info(struct CCcontract_info *cp);
|
||||
CBlockIndex *komodo_blockindex(uint256 hash);
|
||||
CBlockIndex *komodo_chainactive(int32_t height);
|
||||
int32_t komodo_blockheight(uint256 hash);
|
||||
void StartShutdown();
|
||||
|
||||
static const uint256 zeroid;
|
||||
static uint256 ignoretxid;
|
||||
@@ -205,13 +206,13 @@ int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex);
|
||||
|
||||
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, vscript_t vopretNonfungible);
|
||||
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, std::vector<std::pair<uint8_t, vscript_t>> oprets);
|
||||
CScript EncodeTokenImportOpRet(std::vector<uint8_t> origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector<std::pair<uint8_t, vscript_t>> oprets);
|
||||
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::pair<uint8_t, vscript_t> opretWithId);
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> oprets);
|
||||
int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk);
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
|
||||
uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
|
||||
|
||||
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> &oprets);
|
||||
void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible);
|
||||
bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector<CPubKey> &vinPubkeys);
|
||||
@@ -225,8 +226,11 @@ bool priv2addr(char *coinaddr,uint8_t buf33[33],uint8_t priv32[32]);
|
||||
CPubKey buf2pk(uint8_t *buf33);
|
||||
void endiancpy(uint8_t *dest,uint8_t *src,int32_t len);
|
||||
uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout);
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk);
|
||||
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2);
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, std::vector<std::vector<unsigned char>>* vData = NULL);
|
||||
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, std::vector<std::vector<unsigned char>>* vData = NULL);
|
||||
int32_t has_opret(const CTransaction &tx, uint8_t evalcode);
|
||||
CScript getCCopret(const CScript &scriptPubKey);
|
||||
bool makeCCopret(CScript &opret, std::vector<std::vector<unsigned char>> &vData);
|
||||
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk);
|
||||
CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);
|
||||
CC* GetCryptoCondition(CScript const& scriptSig);
|
||||
@@ -292,6 +296,8 @@ void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uin
|
||||
bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen);
|
||||
UniValue ValueFromAmount(const CAmount& amount);
|
||||
|
||||
int64_t TotalPubkeyNormalInputs(const CTransaction &tx, const CPubKey &pubkey);
|
||||
int64_t TotalPubkeyCCInputs(const CTransaction &tx, const CPubKey &pubkey);
|
||||
|
||||
// bitcoin LogPrintStr with category "-debug" cmdarg support for C++ ostringstream:
|
||||
#define CCLOG_INFO 0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
@@ -14,6 +14,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCtokens.h"
|
||||
#include "importcoin.h"
|
||||
|
||||
/* TODO: correct this:
|
||||
-----------------------------
|
||||
@@ -102,22 +103,21 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &
|
||||
|
||||
switch (funcid)
|
||||
{
|
||||
case 'c': // create wont be called to be verified as it has no CC inputs
|
||||
case 'c': // token create should not be validated as it has no CC inputs, so return 'invalid'
|
||||
// token tx structure for 'c':
|
||||
//vin.0: normal input
|
||||
//vout.0: issuance tokenoshis to CC
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.n-1: opreturn EVAL_TOKENS 'c' <tokenname> <description>
|
||||
//if (evalCodeInOpret != EVAL_TOKENS)
|
||||
// return eval->Invalid("unexpected TokenValidate for createtoken");
|
||||
//else
|
||||
return true;
|
||||
return eval->Invalid("incorrect token funcid");
|
||||
|
||||
case 't': // transfer
|
||||
// token tx structure for 't'
|
||||
//vin.0: normal input
|
||||
//vin.1 .. vin.n-1: valid CC outputs
|
||||
//vout.0 to n-2: tokenoshis output to CC
|
||||
//vout.n-2: normal output for change (if any)
|
||||
//vout.n-1: opreturn <other evalcode> 't' tokenid <other contract payload>
|
||||
//vout.n-1: opreturn EVAL_TOKENS 't' tokenid <other contract payload>
|
||||
if (inputs == 0)
|
||||
return eval->Invalid("no token inputs for transfer");
|
||||
|
||||
@@ -129,20 +129,7 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &
|
||||
return eval->Invalid("unexpected token funcid");
|
||||
}
|
||||
|
||||
// forward validation if evalcode in opret is not EVAL_TOKENS
|
||||
// init for forwarding validation call
|
||||
//if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS?
|
||||
// struct CCcontract_info *cpOther = NULL, C;
|
||||
|
||||
// cpOther = CCinit(&C, evalCodeInOpret);
|
||||
// if (cpOther)
|
||||
// return cpOther->validate(cpOther, eval, tx, nIn);
|
||||
// else
|
||||
// return eval->Invalid("unsupported evalcode in opret");
|
||||
//}
|
||||
return true;
|
||||
// what does this do?
|
||||
// return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
}
|
||||
|
||||
// helper funcs:
|
||||
@@ -333,7 +320,8 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true
|
||||
vscript_t vopretExtra, vopretNonfungible;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
uint8_t evalCode = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim
|
||||
uint8_t evalCodeNonfungible = 0;
|
||||
uint8_t evalCode1 = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim
|
||||
uint8_t evalCode2 = 0; // will be checked if zero or not
|
||||
|
||||
// test vouts for possible token use-cases:
|
||||
@@ -354,12 +342,12 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true
|
||||
// non-fungible-eval -> EVAL_TOKENS -> assets-eval
|
||||
|
||||
if (vopretNonfungible.size() > 0)
|
||||
evalCode = vopretNonfungible.begin()[0];
|
||||
evalCodeNonfungible = evalCode1 = vopretNonfungible.begin()[0];
|
||||
if (vopretExtra.size() > 0)
|
||||
evalCode2 = vopretExtra.begin()[0];
|
||||
|
||||
if (evalCode == EVAL_TOKENS && evalCode2 != 0) {
|
||||
evalCode = evalCode2; // for using MakeTokensCC1vout(evalcode,...) instead of MakeCC1vout(EVAL_TOKENS, evalcode...)
|
||||
if (evalCode1 == EVAL_TOKENS && evalCode2 != 0) {
|
||||
evalCode1 = evalCode2; // for using MakeTokensCC1vout(evalcode,...) instead of MakeCC1vout(EVAL_TOKENS, evalcode...)
|
||||
evalCode2 = 0;
|
||||
}
|
||||
|
||||
@@ -369,39 +357,41 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true
|
||||
// maybe this is dual-eval 1 pubkey or 1of2 pubkey vout?
|
||||
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) {
|
||||
// check dual/three-eval 1 pubkey vout with the first pubkey
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0]")) );
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0]")) );
|
||||
if (evalCode2 != 0)
|
||||
// also check in backward evalcode order
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0] backward-eval")) );
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0] backward-eval")) );
|
||||
|
||||
if(voutPubkeys.size() == 2) {
|
||||
// check dual/three eval 1of2 pubkeys vout
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2")) );
|
||||
testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2")) );
|
||||
// check dual/three eval 1 pubkey vout with the second pubkey
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1]")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1]")));
|
||||
if (evalCode2 != 0) {
|
||||
// also check in backward evalcode order:
|
||||
// check dual/three eval 1of2 pubkeys vout
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1of2vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2 backward-eval")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1of2vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2 backward-eval")));
|
||||
// check dual/three eval 1 pubkey vout with the second pubkey
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1] backward-eval")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1] backward-eval")));
|
||||
}
|
||||
}
|
||||
|
||||
// maybe this is like gatewayclaim to single-eval token?
|
||||
if( evalCodeNonfungible == 0 ) // do not allow to convert non-fungible to fungible token
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]), std::string("single-eval cc1 pk[0]")));
|
||||
|
||||
// maybe this is like gatewayclaim to single-eval token?
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]), std::string("single-eval cc1 pk[0]")));
|
||||
// maybe this is like FillSell for non-fungible token?
|
||||
if( evalCode != 0 )
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval-token cc1 pk[0]")));
|
||||
if( evalCode1 != 0 )
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval-token cc1 pk[0]")));
|
||||
if( evalCode2 != 0 )
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval2-token cc1 pk[0]")));
|
||||
|
||||
// the same for pk[1]:
|
||||
if (voutPubkeys.size() == 2) {
|
||||
// the same for pk[1]:
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]), std::string("single-eval cc1 pk[1]")));
|
||||
if (evalCode != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval-token cc1 pk[1]")));
|
||||
if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]), std::string("single-eval cc1 pk[1]")));
|
||||
if (evalCode1 != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval-token cc1 pk[1]")));
|
||||
if (evalCode2 != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval2-token cc1 pk[1]")));
|
||||
}
|
||||
@@ -413,52 +403,95 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true
|
||||
FilterOutTokensUnspendablePk(vinPubkeysUnfiltered, vinPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there)
|
||||
|
||||
for(std::vector<CPubKey>::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) {
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it), std::string("single-eval cc1 self vin pk")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk")));
|
||||
if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it), std::string("single-eval cc1 self vin pk")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk")));
|
||||
|
||||
if (evalCode2 != 0)
|
||||
// also check in backward evalcode order:
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk backward-eval")));
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk backward-eval")));
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
CPubKey origPubkey;
|
||||
vscript_t vorigPubkey;
|
||||
std::string dummyName, dummyDescription;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, oprets) == 0) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() could not decode create opret" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
return 0;
|
||||
// try all test vouts:
|
||||
for (auto t : testVouts) {
|
||||
if (t.first == tx.vout[v]) { // test vout matches
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() valid amount=" << tx.vout[v].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode1 << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
}
|
||||
|
||||
origPubkey = pubkey2pk(vorigPubkey);
|
||||
|
||||
// for 'c' recognize the tokens only to token originator pubkey (but not to unspendable <-- closed sec violation)
|
||||
// maybe this is like gatewayclaim to single-eval token?
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, origPubkey), std::string("single-eval cc1 orig-pk")));
|
||||
// maybe this is like FillSell for non-fungible token?
|
||||
if (evalCode != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, origPubkey), std::string("dual-eval-token cc1 orig-pk")));
|
||||
}
|
||||
else { // funcid == 'c'
|
||||
|
||||
if (!tx.IsCoinImport()) {
|
||||
|
||||
// try all test vouts:
|
||||
for (auto t : testVouts) {
|
||||
if (t.first == tx.vout[v]) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() valid amount=" << tx.vout[v].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
return tx.vout[v].nValue;
|
||||
vscript_t vorigPubkey;
|
||||
std::string dummyName, dummyDescription;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, oprets) == 0) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() could not decode create opret" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CPubKey origPubkey = pubkey2pk(vorigPubkey);
|
||||
|
||||
|
||||
// TODO: add voutPubkeys for 'c' tx
|
||||
|
||||
/* this would not work for imported tokens:
|
||||
// for 'c' recognize the tokens only to token originator pubkey (but not to unspendable <-- closed sec violation)
|
||||
// maybe this is like gatewayclaim to single-eval token?
|
||||
if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token
|
||||
testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, origPubkey), std::string("single-eval cc1 orig-pk")));
|
||||
// maybe this is like FillSell for non-fungible token?
|
||||
if (evalCode1 != 0)
|
||||
testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, origPubkey), std::string("dual-eval-token cc1 orig-pk"))); */
|
||||
|
||||
// note: this would not work if there are several pubkeys in the tokencreator's wallet (AddNormalinputs does not use pubkey param):
|
||||
// for tokenbase tx check that normal inputs sent from origpubkey > cc outputs
|
||||
int64_t ccOutputs = 0;
|
||||
for (auto vout : tx.vout)
|
||||
if (vout.scriptPubKey.IsPayToCryptoCondition() //TODO: add voutPubkey validation
|
||||
&& !IsTokenMarkerVout(vout)) // should not be marker here
|
||||
ccOutputs += vout.nValue;
|
||||
|
||||
int64_t normalInputs = TotalPubkeyNormalInputs(tx, origPubkey); // check if normal inputs are really signed by originator pubkey (someone not cheating with originator pubkey)
|
||||
LOGSTREAM("cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() normalInputs=" << normalInputs << " ccOutputs=" << ccOutputs << " for tokenbase=" << reftokenid.GetHex() << std::endl);
|
||||
|
||||
if (normalInputs >= ccOutputs) {
|
||||
LOGSTREAM("cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() assured normalInputs >= ccOutputs" << " for tokenbase=" << reftokenid.GetHex() << std::endl);
|
||||
if (!IsTokenMarkerVout(tx.vout[v])) // exclude marker
|
||||
return tx.vout[v].nValue;
|
||||
else
|
||||
return 0; // vout is good, but do not take marker into account
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() skipping vout not fulfilled normalInputs >= ccOutput" << " for tokenbase=" << reftokenid.GetHex() << " normalInputs=" << normalInputs << " ccOutputs=" << ccOutputs << std::endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() no valid vouts evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
else {
|
||||
// imported tokens are checked in the eval::ImportCoin() validation code
|
||||
if (!IsTokenMarkerVout(tx.vout[v])) // exclude marker
|
||||
return tx.vout[v].nValue;
|
||||
else
|
||||
return 0; // vout is good, but do not take marker into account
|
||||
}
|
||||
}
|
||||
LOGSTREAM("cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() no valid vouts evalCode=" << (int)evalCode1 << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl);
|
||||
}
|
||||
|
||||
//std::cerr << indentStr; fprintf(stderr,"IsTokensvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str());
|
||||
}
|
||||
//std::cerr << indentStr; fprintf(stderr,"IsTokensvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
bool IsTokenMarkerVout(CTxOut vout) {
|
||||
struct CCcontract_info *cpTokens, CCtokens_info;
|
||||
cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS);
|
||||
return vout == MakeCC1vout(EVAL_TOKENS, vout.nValue, GetUnspendable(cpTokens, NULL));
|
||||
}
|
||||
|
||||
// compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs)
|
||||
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cp, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 reftokenid)
|
||||
{
|
||||
@@ -582,6 +615,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C
|
||||
GetTokensCCaddress(cp, tokenaddr, pk);
|
||||
SetCCunspents(unspentOutputs, tokenaddr,true);
|
||||
|
||||
|
||||
if (unspentOutputs.empty()) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() no utxos for token dual/three eval addr=" << tokenaddr << " evalcode=" << (int)cp->evalcode << " additionalTokensEvalcode2=" << (int)cp->additionalTokensEvalcode2 << std::endl);
|
||||
}
|
||||
@@ -747,7 +781,7 @@ CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey) {
|
||||
return CPubKey(); //return invalid pubkey
|
||||
}
|
||||
|
||||
|
||||
// returns token creation signed raw tx
|
||||
std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, std::string description, vscript_t nonfungibleData)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
@@ -767,7 +801,7 @@ std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, st
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
if (name.size() > 32 || description.size() > 4096) // this is also checked on rpc level
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "name len=" << name.size() << " or description len=" << description.size() << " is too big" << std::endl);
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "name len=" << name.size() << " or description len=" << description.size() << " is too big" << std::endl);
|
||||
CCerror = "name should be <= 32, description should be <= 4096";
|
||||
return("");
|
||||
}
|
||||
@@ -777,6 +811,13 @@ std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, st
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, tokensupply + 2 * txfee, 64) > 0)
|
||||
{
|
||||
|
||||
int64_t mypkInputs = TotalPubkeyNormalInputs(mtx, mypk);
|
||||
if (mypkInputs < tokensupply) { // check that tokens amount are really issued with mypk (because in the wallet there maybe other privkeys)
|
||||
CCerror = "some inputs signed not with -pubkey=pk";
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
uint8_t destEvalCode = EVAL_TOKENS;
|
||||
if( nonfungibleData.size() > 0 )
|
||||
destEvalCode = nonfungibleData.begin()[0];
|
||||
@@ -843,7 +884,7 @@ std::string TokenTransfer(int64_t txfee, uint256 tokenid, vscript_t destpubkey,
|
||||
}
|
||||
else {
|
||||
CCerror = strprintf("no token inputs");
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << total << std::endl);
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << " for amount=" << total << std::endl);
|
||||
}
|
||||
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
|
||||
}
|
||||
@@ -880,7 +921,7 @@ UniValue TokenInfo(uint256 tokenid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
uint256 hashBlock;
|
||||
CTransaction vintx;
|
||||
CTransaction tokenbaseTx;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
vscript_t vopretNonfungible;
|
||||
@@ -889,14 +930,14 @@ UniValue TokenInfo(uint256 tokenid)
|
||||
|
||||
cpTokens = CCinit(&tokensCCinfo, EVAL_TOKENS);
|
||||
|
||||
if( !GetTransaction(tokenid, vintx, hashBlock, false) )
|
||||
if( !GetTransaction(tokenid, tokenbaseTx, hashBlock, false) )
|
||||
{
|
||||
fprintf(stderr, "TokenInfo() cant find tokenid\n");
|
||||
result.push_back(Pair("result", "error"));
|
||||
result.push_back(Pair("error", "cant find tokenid"));
|
||||
return(result);
|
||||
}
|
||||
if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description, oprets) != 'c')
|
||||
if (tokenbaseTx.vout.size() > 0 && DecodeTokenCreateOpRet(tokenbaseTx.vout[tokenbaseTx.vout.size() - 1].scriptPubKey, origpubkey, name, description, oprets) != 'c')
|
||||
{
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenInfo() passed tokenid isnt token creation txid" << std::endl);
|
||||
result.push_back(Pair("result", "error"));
|
||||
@@ -909,8 +950,8 @@ UniValue TokenInfo(uint256 tokenid)
|
||||
result.push_back(Pair("name", name));
|
||||
|
||||
int64_t supply = 0, output;
|
||||
for (int v = 0; v < vintx.vout.size() - 1; v++)
|
||||
if ((output = IsTokensvout(false, true, cpTokens, NULL, vintx, v, tokenid)) > 0)
|
||||
for (int v = 0; v < tokenbaseTx.vout.size() - 1; v++)
|
||||
if ((output = IsTokensvout(false, true, cpTokens, NULL, tokenbaseTx, v, tokenid)) > 0)
|
||||
supply += output;
|
||||
result.push_back(Pair("supply", supply));
|
||||
result.push_back(Pair("description", description));
|
||||
@@ -919,6 +960,40 @@ UniValue TokenInfo(uint256 tokenid)
|
||||
if( !vopretNonfungible.empty() )
|
||||
result.push_back(Pair("data", HexStr(vopretNonfungible)));
|
||||
|
||||
if (tokenbaseTx.IsCoinImport()) { // if imported token
|
||||
ImportProof proof;
|
||||
CTransaction burnTx;
|
||||
std::vector<CTxOut> payouts;
|
||||
CTxDestination importaddress;
|
||||
|
||||
std::string sourceSymbol = "can't decode";
|
||||
std::string sourceTokenId = "can't decode";
|
||||
|
||||
if (UnmarshalImportTx(tokenbaseTx, proof, burnTx, payouts))
|
||||
{
|
||||
// extract op_return to get burn source chain.
|
||||
std::vector<uint8_t> burnOpret;
|
||||
std::string targetSymbol;
|
||||
uint32_t targetCCid;
|
||||
uint256 payoutsHash;
|
||||
std::vector<uint8_t> rawproof;
|
||||
if (UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) {
|
||||
if (rawproof.size() > 0) {
|
||||
CTransaction tokenbasetx;
|
||||
E_UNMARSHAL(rawproof, ss >> sourceSymbol;
|
||||
if (!ss.eof())
|
||||
ss >> tokenbasetx);
|
||||
|
||||
if (!tokenbasetx.IsNull())
|
||||
sourceTokenId = tokenbasetx.GetHash().GetHex();
|
||||
}
|
||||
}
|
||||
}
|
||||
result.push_back(Pair("IsImported", "yes"));
|
||||
result.push_back(Pair("sourceChain", sourceSymbol));
|
||||
result.push_back(Pair("sourceTokenId", sourceTokenId));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, st
|
||||
std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector<uint8_t> destpubkey, int64_t total);
|
||||
int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, uint256 reftokenid);
|
||||
CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey);
|
||||
bool IsTokenMarkerVout(CTxOut vout);
|
||||
|
||||
int64_t GetTokenBalance(CPubKey pk, uint256 tokenid);
|
||||
UniValue TokenInfo(uint256 tokenid);
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
// encode decode tokens opret
|
||||
// (moved to a separate file to enable linking lib common.so with importcoin.cpp)
|
||||
// make token cryptoconditions and vouts
|
||||
// This code was moved to a separate source file to enable linking libcommon.so (with importcoin.cpp which depends on some token functions)
|
||||
|
||||
#include "CCtokens.h"
|
||||
|
||||
@@ -44,6 +60,7 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey,
|
||||
return(opret);
|
||||
}
|
||||
|
||||
/*
|
||||
// opret 'i' for imported tokens
|
||||
CScript EncodeTokenImportOpRet(std::vector<uint8_t> origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector<std::pair<uint8_t, vscript_t>> oprets)
|
||||
{
|
||||
@@ -62,7 +79,7 @@ CScript EncodeTokenImportOpRet(std::vector<uint8_t> origpubkey, std::string name
|
||||
});
|
||||
return(opret);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::pair<uint8_t, vscript_t> opretWithId)
|
||||
@@ -158,37 +175,9 @@ uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t>
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// for imported tokens
|
||||
uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
|
||||
{
|
||||
vscript_t vopret, vblob;
|
||||
uint8_t dummyEvalcode, funcid, opretId = 0;
|
||||
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
oprets.clear();
|
||||
|
||||
if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'i')
|
||||
{
|
||||
if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description; ss >> srctokenid;
|
||||
while (!ss.eof()) {
|
||||
ss >> opretId;
|
||||
if (!ss.eof()) {
|
||||
ss >> vblob;
|
||||
oprets.push_back(std::make_pair(opretId, vblob));
|
||||
}
|
||||
}))
|
||||
{
|
||||
srctokenid = revuint256(srctokenid); // do not forget this
|
||||
return(funcid);
|
||||
}
|
||||
}
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenImportOpRet() incorrect token import opret" << std::endl);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// decodes token opret:
|
||||
// decode token opret:
|
||||
// for 't' returns all data from opret, vopretExtra contains other contract's data (currently only assets').
|
||||
// for 'c' and 'i' returns only funcid. NOTE: nonfungible data is not returned
|
||||
// for 'c' returns only funcid. NOTE: nonfungible data is not returned
|
||||
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
|
||||
{
|
||||
vscript_t vopret, vblob, dummyPubkey, vnonfungibleDummy;
|
||||
@@ -207,9 +196,6 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, ui
|
||||
|
||||
if (script != NULL && vopret.size() > 2)
|
||||
{
|
||||
// NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set!
|
||||
// bool isEof = true;
|
||||
|
||||
evalCodeTokens = script[0];
|
||||
if (evalCodeTokens != EVAL_TOKENS) {
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect evalcode in tokens opret" << std::endl);
|
||||
@@ -217,15 +203,13 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, ui
|
||||
}
|
||||
|
||||
funcId = script[1];
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet decoded funcId=" << (char)(funcId ? funcId : ' ') << std::endl);
|
||||
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet() decoded funcId=" << (char)(funcId ? funcId : ' ') << std::endl);
|
||||
|
||||
switch (funcId)
|
||||
{
|
||||
case 'c':
|
||||
return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, oprets);
|
||||
case 'i':
|
||||
return DecodeTokenImportOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, dummySrcTokenId, oprets);
|
||||
//break;
|
||||
|
||||
case 't':
|
||||
|
||||
// compatibility with old-style rogue or assets data (with no opretid):
|
||||
@@ -293,4 +277,75 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, ui
|
||||
}
|
||||
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) 1of2 cryptocondition:
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
// make 1of2 sigs cond
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk1));
|
||||
pks.push_back(CCNewSecp256k1(pk2));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode)));
|
||||
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
if (evalcode2 != 0)
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) 1of2 cryptocondition:
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) {
|
||||
return MakeTokensCCcond1of2(evalcode, 0, pk1, pk2);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) cryptocondition:
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode)));
|
||||
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
if (evalcode2 != 0)
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // signature
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) cryptocondition:
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) {
|
||||
return MakeTokensCCcond1(evalcode, 0, pk);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) 1of2 cc vout:
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1of2(evalcode, evalcode2, pk1, pk2);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) 1of2 cc vout:
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) {
|
||||
return MakeTokensCC1of2vout(evalcode, 0, nValue, pk1, pk2);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) cc vout:
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) cc vout:
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) {
|
||||
return MakeTokensCC1vout(evalcode, 0, nValue, pk);
|
||||
}
|
||||
|
||||
@@ -58,97 +58,76 @@ CC *MakeCCcond1(uint8_t evalcode,CPubKey pk)
|
||||
return CCNewThreshold(2, {condCC, Sig});
|
||||
}
|
||||
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk)
|
||||
int32_t has_opret(const CTransaction &tx, uint8_t evalcode)
|
||||
{
|
||||
int i = 0;
|
||||
for ( auto vout : tx.vout )
|
||||
{
|
||||
if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode )
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) )
|
||||
{
|
||||
//opret << E_MARSHAL(ss << vParams[0]);
|
||||
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;
|
||||
}
|
||||
|
||||
bool makeCCopret(CScript &opret, std::vector<std::vector<unsigned char>> &vData)
|
||||
{
|
||||
if ( opret.empty() )
|
||||
return false;
|
||||
vData.push_back(std::vector<unsigned char>(opret.begin(), opret.end()));
|
||||
return true;
|
||||
}
|
||||
|
||||
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, std::vector<std::vector<unsigned char>>* vData)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeCCcond1(evalcode,pk);
|
||||
vout = CTxOut(nValue,CCPubKey(payoutCond));
|
||||
if ( vData )
|
||||
{
|
||||
//std::vector<std::vector<unsigned char>> vtmpData = std::vector<std::vector<unsigned char>>(vData->begin(), vData->end());
|
||||
std::vector<CPubKey> vPubKeys = std::vector<CPubKey>();
|
||||
//vPubKeys.push_back(pk);
|
||||
COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, ( * vData));
|
||||
vout.scriptPubKey << ccp.AsVector() << OP_DROP;
|
||||
}
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
|
||||
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, std::vector<std::vector<unsigned char>>* vData)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2);
|
||||
vout = CTxOut(nValue,CCPubKey(payoutCond));
|
||||
if ( vData )
|
||||
{
|
||||
//std::vector<std::vector<unsigned char>> vtmpData = std::vector<std::vector<unsigned char>>(vData->begin(), vData->end());
|
||||
std::vector<CPubKey> vPubKeys = std::vector<CPubKey>();
|
||||
// skip pubkeys. These need to maybe be optional and we need some way to get them out that is easy!
|
||||
//vPubKeys.push_back(pk1);
|
||||
//vPubKeys.push_back(pk2);
|
||||
COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, ( * vData));
|
||||
vout.scriptPubKey << ccp.AsVector() << OP_DROP;
|
||||
}
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) 1of2 cryptocondition:
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
// make 1of2 sigs cond
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk1));
|
||||
pks.push_back(CCNewSecp256k1(pk2));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back( CCNewEval(E_MARSHAL(ss << evalcode)) );
|
||||
if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
if( evalcode2 != 0 )
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) 1of2 cryptocondition:
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) {
|
||||
return MakeTokensCCcond1of2(evalcode, 0, pk1, pk2);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) cryptocondition:
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode)));
|
||||
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
if (evalcode2 != 0)
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // signature
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) cryptocondition:
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) {
|
||||
return MakeTokensCCcond1(evalcode, 0, pk);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) 1of2 cc vout:
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1of2(evalcode, evalcode2, pk1, pk2);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) 1of2 cc vout:
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) {
|
||||
return MakeTokensCC1of2vout(evalcode, 0, nValue, pk1, pk2);
|
||||
}
|
||||
|
||||
// make three-eval (token+evalcode+evalcode2) cc vout:
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
// overload to make two-eval (token+evalcode) cc vout:
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) {
|
||||
return MakeTokensCC1vout(evalcode, 0, nValue, pk);
|
||||
}
|
||||
|
||||
|
||||
CC* GetCryptoCondition(CScript const& scriptSig)
|
||||
{
|
||||
auto pc = scriptSig.begin();
|
||||
@@ -170,8 +149,12 @@ bool IsCCInput(CScript const& scriptSig)
|
||||
|
||||
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime)
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
CCoinsView dummy;
|
||||
CCoinsViewCache view(&dummy);
|
||||
int64_t interest; uint64_t valuein;
|
||||
CCoinsViewCache &view = *pcoinsTip;
|
||||
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
|
||||
view.SetBackend(viewMemPool);
|
||||
valuein = view.GetValueIn(height,&interest,tx,blocktime);
|
||||
if ( valuein-tx.GetValueOut() > txfee )
|
||||
{
|
||||
@@ -640,7 +623,7 @@ bool komodo_txnotarizedconfirmed(uint256 txid)
|
||||
fprintf(stderr,"komodo_txnotarizedconfirmed no hashBlock for txid %s\n",txid.ToString().c_str());
|
||||
return(0);
|
||||
}
|
||||
else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txheight= pindex->GetHeight()) <= 0 )
|
||||
else if ( (pindex= komodo_blockindex(hashBlock)) == 0 || (txheight= pindex->GetHeight()) <= 0 )
|
||||
{
|
||||
fprintf(stderr,"komodo_txnotarizedconfirmed no txheight.%d %p for txid %s\n",txheight,pindex,txid.ToString().c_str());
|
||||
return(0);
|
||||
@@ -692,6 +675,57 @@ CPubKey check_signing_pubkey(CScript scriptSig)
|
||||
return CPubKey();
|
||||
}
|
||||
|
||||
|
||||
// returns total of normal inputs signed with this pubkey
|
||||
int64_t TotalPubkeyNormalInputs(const CTransaction &tx, const CPubKey &pubkey)
|
||||
{
|
||||
int64_t total = 0;
|
||||
for (auto vin : tx.vin) {
|
||||
CTransaction vintx;
|
||||
uint256 hashBlock;
|
||||
if (!IsCCInput(vin.scriptSig) && myGetTransaction(vin.prevout.hash, vintx, hashBlock)) {
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
std::vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
|
||||
if (Solver(vintx.vout[vin.prevout.n].scriptPubKey, whichType, vSolutions)) {
|
||||
switch (whichType) {
|
||||
case TX_PUBKEY:
|
||||
if (pubkey == CPubKey(vSolutions[0])) // is my input?
|
||||
total += vintx.vout[vin.prevout.n].nValue;
|
||||
break;
|
||||
case TX_PUBKEYHASH:
|
||||
if (pubkey.GetID() == CKeyID(uint160(vSolutions[0]))) // is my input?
|
||||
total += vintx.vout[vin.prevout.n].nValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
// returns total of CC inputs signed with this pubkey
|
||||
int64_t TotalPubkeyCCInputs(const CTransaction &tx, const CPubKey &pubkey)
|
||||
{
|
||||
int64_t total = 0;
|
||||
for (auto vin : tx.vin) {
|
||||
if (IsCCInput(vin.scriptSig)) {
|
||||
CPubKey vinPubkey = check_signing_pubkey(vin.scriptSig);
|
||||
if (vinPubkey.IsValid()) {
|
||||
if (vinPubkey == pubkey) {
|
||||
CTransaction vintx;
|
||||
uint256 hashBlock;
|
||||
if (myGetTransaction(vin.prevout.hash, vintx, hashBlock)) {
|
||||
total += vintx.vout[vin.prevout.n].nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
|
||||
{
|
||||
CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
CScript custom_opret(uint8_t funcid,CPubKey pk)
|
||||
{
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_CUSTOM;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk);
|
||||
return(opret);
|
||||
@@ -64,10 +64,17 @@ UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,COIN+txfee,64) >= COIN+txfee ) // add utxo to mtx
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk)); // make vout0
|
||||
// add opreturn, change is automatically added and tx is properly signed
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,custom_opret('1',mypk));
|
||||
return(custom_rawtxresult(result,rawtx,broadcastflag));
|
||||
// make op_return payload as normal.
|
||||
CScript opret = custom_opret('1',mypk);
|
||||
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
|
||||
if ( makeCCopret(opret, vData) )
|
||||
{
|
||||
// make vout0 with op_return included as payload.
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData));
|
||||
fprintf(stderr, "vout size2.%li\n", mtx.vout.size());
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript());
|
||||
return(custom_rawtxresult(result,rawtx,broadcastflag));
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
@@ -75,14 +82,24 @@ UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||
bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
||||
{
|
||||
char expectedaddress[64]; CPubKey pk;
|
||||
if ( tx.vout.size() != 2 ) // make sure the tx only has 2 outputs
|
||||
CScript opret; int32_t numvout;
|
||||
if ( has_opret(tx, EVAL_CUSTOM) == 0 )
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
|
||||
opret = getCCopret(tx.vout[0].scriptPubKey);
|
||||
numvout = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
opret = tx.vout[1].scriptPubKey;
|
||||
numvout = 2;
|
||||
}
|
||||
if ( tx.vout.size() != numvout ) // make sure the tx only has appropriate outputs
|
||||
return eval->Invalid("invalid number of vouts");
|
||||
else if ( custom_opretdecode(pk,tx.vout[1].scriptPubKey) != '1' ) // verify has opreturn
|
||||
else if ( custom_opretdecode(pk,opret) != '1' ) // verify opreturn payload
|
||||
return eval->Invalid("invalid opreturn");
|
||||
GetCCaddress(cp,expectedaddress,pk);
|
||||
if ( IsCClibvout(cp,tx,0,expectedaddress) == COIN ) // make sure amount and destination matches
|
||||
return(true);
|
||||
else return eval->Invalid("invalid vout0 amount");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -664,6 +664,7 @@ int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr)
|
||||
free(retstr);
|
||||
return(0);
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname)
|
||||
|
||||
@@ -1662,7 +1662,7 @@ void *dealer0_loop(void *_arg)
|
||||
if ( (cp= Diceinit(fundingPubKey,dealer0_fundingtxid,&C,planstr,txfee,mypk,dicepk,refsbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"error initializing dealer0_loop\n");
|
||||
exit(-1);
|
||||
StartShutdown();
|
||||
}
|
||||
fprintf(stderr,"dealer0 node running\n");
|
||||
height = lastht = 0;
|
||||
|
||||
@@ -571,8 +571,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("invalid gatewaysbind OP_RETURN data!");
|
||||
else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 )
|
||||
return eval->Invalid("vin.0 is normal for gatewaysbind!");
|
||||
else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 )
|
||||
return eval->Invalid("vin.1 is CC for gatewaysbind!");
|
||||
else if ( ConstrainVout(tmptx.vout[0],1,gatewaystokensaddr,totalsupply)==0)
|
||||
return eval->Invalid("invalid tokens to gateways vout for gatewaysbind!");
|
||||
else if ( ConstrainVout(tmptx.vout[1],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0)
|
||||
@@ -599,6 +597,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid(validationError);
|
||||
}
|
||||
else if ( DecodeOraclesCreateOpRet(tmptx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' )
|
||||
return eval->Invalid("invalid oraclescreate OP_RETURN data");
|
||||
else if (refcoin!=name)
|
||||
{
|
||||
sprintf(validationError,"mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str());
|
||||
return eval->Invalid(validationError);
|
||||
@@ -632,10 +632,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("invalid gatewaysdeposittxid!");
|
||||
else if (IsCCInput(tx.vin[0].scriptSig) != 0)
|
||||
return eval->Invalid("vin.0 is normal for gatewaysclaim!");
|
||||
else if (IsCCInput(tx.vin[1].scriptSig) == 0)
|
||||
return eval->Invalid("vin.1 is CC for gatewaysclaim!");
|
||||
else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || myGetTransaction(tx.vin[2].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin.2 is CC marker for gatewaysclaim or invalid marker amount!");
|
||||
else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewaysclaim or invalid marker amount!");
|
||||
else if (_GetCCaddress(destaddr,EVAL_TOKENS,pubkey)==0 || ConstrainVout(tx.vout[0],1,destaddr,amount)==0)
|
||||
return eval->Invalid("invalid vout tokens to destpub for gatewaysclaim!");
|
||||
else if (numvouts>2 && (myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || ConstrainVout(tx.vout[1],1,gatewaystokensaddr,tmptx.vout[tx.vin[1].prevout.n].nValue-amount)==0))
|
||||
@@ -695,8 +693,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("refcoin different than in bind tx");
|
||||
else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 )
|
||||
return eval->Invalid("vin.0 is normal for gatewaysWithdraw!");
|
||||
else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 )
|
||||
return eval->Invalid("vin.1 is CC for gatewaysWithdraw!");
|
||||
else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0)
|
||||
return eval->Invalid("invalid marker vout for gatewaysWithdraw!");
|
||||
else if ( ConstrainVout(tmptx.vout[1],1,gatewaystokensaddr,amount)==0)
|
||||
@@ -717,8 +713,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!");
|
||||
else if (IsCCInput(tx.vin[0].scriptSig) != 0)
|
||||
return eval->Invalid("vin.0 is normal for gatewayspartialsign!");
|
||||
else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin.1 is CC marker for gatewayspartialsign or invalid marker amount!");
|
||||
else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewayspartialsign or invalid marker amount!");
|
||||
else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 )
|
||||
return eval->Invalid("vout.0 invalid marker for gatewayspartialsign!");
|
||||
else if (K>M)
|
||||
@@ -739,8 +735,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("refcoin different than in bind tx");
|
||||
else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 )
|
||||
return eval->Invalid("vin.0 is normal for gatewaysWithdraw!");
|
||||
else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 )
|
||||
return eval->Invalid("vin.1 is CC for gatewaysWithdraw!");
|
||||
else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0)
|
||||
return eval->Invalid("invalid marker vout for gatewaysWithdraw!");
|
||||
else if ( ConstrainVout(tmptx.vout[1],1,gatewaystokensaddr,amount)==0)
|
||||
@@ -761,8 +755,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!");
|
||||
else if (IsCCInput(tx.vin[0].scriptSig) != 0)
|
||||
return eval->Invalid("vin.0 is normal for gatewayscompletesigning!");
|
||||
else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin.1 is CC marker for gatewayscompletesigning or invalid marker amount!");
|
||||
else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewayscompletesigning or invalid marker amount!");
|
||||
else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 )
|
||||
return eval->Invalid("vout.0 invalid marker for gatewayscompletesigning!");
|
||||
else if (K<M)
|
||||
@@ -800,8 +794,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!");
|
||||
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
|
||||
return eval->Invalid("vin.0 is normal for gatewaysmarkdone!");
|
||||
else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin.1 is CC marker for gatewaysmarkdone or invalid marker amount!");
|
||||
else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE)
|
||||
return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewaysmarkdone or invalid marker amount!");
|
||||
else if (K<M)
|
||||
return eval->Invalid("invalid number of signs!");
|
||||
break;
|
||||
|
||||
@@ -20,47 +20,35 @@
|
||||
#include "primitives/transaction.h"
|
||||
#include "cc/CCinclude.h"
|
||||
#include <openssl/sha.h>
|
||||
#include "cc/CCtokens.h"
|
||||
|
||||
#include "key_io.h"
|
||||
#define CODA_BURN_ADDRESS "KPrrRoPfHOnNpZZQ6laHXdQDkSQDkVHaN0V+LizLlHxz7NaA59sBAAAA"
|
||||
/*
|
||||
* CC Eval method for import coin.
|
||||
*
|
||||
* This method should control every parameter of the ImportCoin transaction, since it has no signature
|
||||
* to protect it from malleability.
|
||||
|
||||
##### 0xffffffff is a special CCid for single chain/dual daemon imports
|
||||
*/
|
||||
|
||||
extern std::string ASSETCHAINS_SELFIMPORT;
|
||||
extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT;
|
||||
extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
extern uint256 KOMODO_EARLYTXID;
|
||||
|
||||
// utilities from gateways.cpp
|
||||
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids);
|
||||
uint256 GatewaysReverseScan(uint256 &txid, int32_t height, uint256 reforacletxid, uint256 batontxid);
|
||||
int32_t GatewaysCointxidExists(struct CCcontract_info *cp, uint256 cointxid);
|
||||
uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector<CPubKey> &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype);
|
||||
uint8_t DecodeImportGatewayBindOpRet(char *burnaddr,const CScript &scriptPubKey,std::string &coin,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector<CPubKey> &importgatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype);
|
||||
int64_t ImportGatewayVerify(char *refburnaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 burntxid,const std::string deposithex,std::vector<uint8_t>proof,uint256 merkleroot,CPubKey destpub,uint8_t taddr,uint8_t prefix,uint8_t prefix2);
|
||||
char *nonportable_path(char *str);
|
||||
char *portable_path(char *str);
|
||||
void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep);
|
||||
void *filestr(long *allocsizep,char *_fname);
|
||||
|
||||
// ac_import=chain support:
|
||||
// encode opret for gateways import
|
||||
CScript EncodeImportTxOpRet(uint32_t targetCCid, std::string coin, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint256 bindtxid, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
CScript EncodeCodaImportTxOpRet(uint32_t targetCCid, std::string coin, std::string burntx, uint256 bindtxid, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << burntx << bindtxid << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2,char const *arg3,char const *arg4,char const *arg5)
|
||||
{
|
||||
char cmdstr[5000],fname[256],*jsonstr;
|
||||
@@ -81,165 +69,66 @@ cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2,
|
||||
return(retjson);
|
||||
}
|
||||
|
||||
bool ImportCoinGatewaysVerify(CTransaction oracletx, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vector<uint8_t>proof, uint256 merkleroot)
|
||||
{
|
||||
std::vector<uint256> txids;
|
||||
uint256 proofroot;
|
||||
std::string name, description, format;
|
||||
int32_t i, numvouts;
|
||||
|
||||
if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in trusted merkleroot" << std::endl);
|
||||
return true;
|
||||
}
|
||||
|
||||
// make import tx with burntx and its proof of existence
|
||||
// std::string MakeGatewaysImportTx(uint64_t txfee, uint256 oracletxid, int32_t height, std::string refcoin, std::vector<uint8_t> proof, std::string rawburntx, int32_t ivout, uint256 burntxid,std::string destaddr)
|
||||
// {
|
||||
// CMutableTransaction burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
// CTransaction oracletx,regtx; CPubKey regpk;
|
||||
// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts;
|
||||
// std::string name,desc,format; std::vector<CTxOut> vouts;
|
||||
// std::vector<CPubKey> pubkeys; std::vector<uint256>txids;
|
||||
// char markeraddr[64]; int64_t datafee;
|
||||
// std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
|
||||
// if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx))
|
||||
// return std::string("");
|
||||
// CAmount amount = GetCoinImportValue(burntx); // equal to int64_t
|
||||
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl);
|
||||
// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C')
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// if (name!=refcoin || format!="Ihh")
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// CCtxidaddr(markeraddr,oracletxid);
|
||||
// SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
// for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
// {
|
||||
// txid = it->first.txhash;
|
||||
// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0
|
||||
// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid )
|
||||
// {
|
||||
// pubkeys.push_back(regpk);
|
||||
// n++;
|
||||
// }
|
||||
// }
|
||||
// merkleroot = zeroid;
|
||||
// for (i = m = 0; i < n; i++)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl);
|
||||
// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
|
||||
// {
|
||||
// if (merkleroot == zeroid)
|
||||
// merkleroot = mhash, m = 1;
|
||||
// else if (mhash == merkleroot)
|
||||
// m ++;
|
||||
// txids.push_back(txid);
|
||||
// }
|
||||
// }
|
||||
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl);
|
||||
// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
|
||||
// return("");
|
||||
// }
|
||||
// proofroot = BitcoinGetProofMerkleRoot(proof, txids);
|
||||
// if (proofroot != merkleroot)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// // check the burntxid is in the proof:
|
||||
// if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid proof for this burntxid=" << burntxid.GetHex() << std::endl);
|
||||
// return("");
|
||||
// }
|
||||
// burntx.vout.push_back(MakeBurnOutput(amount,0xffffffff,refcoin,vouts,proof,oracletxid,height));
|
||||
// std::vector<uint256> leaftxids;
|
||||
// BitcoinGetProofMerkleRoot(proof, leaftxids);
|
||||
// MerkleBranch newBranch(0, leaftxids);
|
||||
// TxProof txProof = std::make_pair(burntxid, newBranch);
|
||||
// CTxDestination dest = DecodeDestination(destaddr.c_str());
|
||||
// CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
// vouts.push_back(CTxOut(amount,scriptPubKey));
|
||||
// return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts)));
|
||||
// }
|
||||
|
||||
// makes source tx for self import tx
|
||||
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx)
|
||||
CMutableTransaction MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount)
|
||||
{
|
||||
const int64_t txfee = 10000;
|
||||
int64_t inputs, change;
|
||||
CPubKey myPubKey = Mypubkey();
|
||||
struct CCcontract_info *cpDummy, C;
|
||||
|
||||
cpDummy = CCinit(&C, EVAL_TOKENS);
|
||||
cpDummy = CCinit(&C, EVAL_TOKENS); // this is just for FinalizeCCTx to work
|
||||
|
||||
mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
|
||||
if( (inputs = AddNormalinputs(mtx, myPubKey, txfee, 4)) == 0 ) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx: cannot find normal imputs for txfee" << std::endl);
|
||||
return std::string("");
|
||||
if (AddNormalinputs(mtx, myPubKey, 2 * txfee, 4) == 0) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx() warning: cannot find normal inputs for txfee" << std::endl);
|
||||
}
|
||||
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
mtx.vout.push_back(CTxOut(txfee, scriptPubKey));
|
||||
change = inputs - txfee;
|
||||
if( change != 0 )
|
||||
mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG));
|
||||
|
||||
//make opret with amount:
|
||||
return FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount));
|
||||
//make opret with 'burned' amount:
|
||||
FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount));
|
||||
return mtx;
|
||||
}
|
||||
|
||||
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
|
||||
int32_t CheckVin0PubKey(const CTransaction &sourcetx)
|
||||
// make sure vin is signed by pubkey33
|
||||
bool CheckVinPubKey(const CTransaction &sourcetx, int32_t i, uint8_t pubkey33[33])
|
||||
{
|
||||
CTransaction vintx;
|
||||
uint256 blockHash;
|
||||
char destaddr[64], pkaddr[64];
|
||||
|
||||
if( !myGetTransaction(sourcetx.vin[0].prevout.hash, vintx, blockHash) ) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() could not load vintx" << sourcetx.vin[0].prevout.hash.GetHex() << std::endl);
|
||||
return(-1);
|
||||
if (i < 0 || i >= sourcetx.vin.size())
|
||||
return false;
|
||||
|
||||
if( !myGetTransaction(sourcetx.vin[i].prevout.hash, vintx, blockHash) ) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVinPubKey() could not load vintx" << sourcetx.vin[i].prevout.hash.GetHex() << std::endl);
|
||||
return false;
|
||||
}
|
||||
if( sourcetx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[0].prevout.n].scriptPubKey) != 0 )
|
||||
if( sourcetx.vin[i].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[i].prevout.n].scriptPubKey) != 0 )
|
||||
{
|
||||
pubkey2addr(pkaddr, ASSETCHAINS_OVERRIDE_PUBKEY33);
|
||||
pubkey2addr(pkaddr, pubkey33);
|
||||
if (strcmp(pkaddr, destaddr) == 0) {
|
||||
return(0);
|
||||
return true;
|
||||
}
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() mismatched vin0[prevout.n=" << sourcetx.vin[0].prevout.n << "] -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl);
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVinPubKey() mismatched vin[" << i << "].prevout.n=" << sourcetx.vin[i].prevout.n << " -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl);
|
||||
}
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ac_import=PUBKEY support:
|
||||
// prepare a tx for creating import tx and quasi-burn tx
|
||||
int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount) // find burnTx with hash from "other" daemon
|
||||
int32_t GetSelfimportProof(const CMutableTransaction sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull) // find burnTx with hash from "other" daemon
|
||||
{
|
||||
MerkleBranch newBranch;
|
||||
CMutableTransaction tmpmtx;
|
||||
CTransaction sourcetx;
|
||||
//CTransaction sourcetx;
|
||||
|
||||
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
|
||||
/*
|
||||
if (!E_UNMARSHAL(ParseHex(rawsourcetx), ss >> sourcetx)) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: could not unmarshal source tx" << std::endl);
|
||||
return(-1);
|
||||
@@ -248,9 +137,9 @@ int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript
|
||||
if (sourcetx.vout.size() == 0) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: vout size is 0" << std::endl);
|
||||
return -1;
|
||||
}
|
||||
} */
|
||||
|
||||
if (ivout < 0) { // "ivout < 0" means "find"
|
||||
/*if (ivout < 0) { // "ivout < 0" means "find"
|
||||
// try to find vout
|
||||
CPubKey myPubkey = Mypubkey();
|
||||
ivout = 0;
|
||||
@@ -262,38 +151,49 @@ int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript
|
||||
if (ivout >= sourcetx.vout.size()) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: needed vout not found" << std::endl);
|
||||
return -1;
|
||||
}
|
||||
} */
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl);
|
||||
int32_t ivout = 0;
|
||||
|
||||
scriptPubKey = sourcetx.vout[ivout].scriptPubKey;
|
||||
// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl);
|
||||
|
||||
CScript scriptPubKey = sourceMtx.vout[ivout].scriptPubKey;
|
||||
|
||||
//mtx is template for import tx
|
||||
mtx = sourcetx;
|
||||
mtx.fOverwintered = tmpmtx.fOverwintered;
|
||||
templateMtx = sourceMtx;
|
||||
templateMtx.fOverwintered = tmpmtx.fOverwintered;
|
||||
|
||||
//malleability fix for burn tx:
|
||||
//mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
|
||||
mtx.nExpiryHeight = sourcetx.nExpiryHeight;
|
||||
templateMtx.nExpiryHeight = sourceMtx.nExpiryHeight;
|
||||
|
||||
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
|
||||
mtx.nVersion = tmpmtx.nVersion;
|
||||
mtx.vout.clear();
|
||||
mtx.vout.resize(1);
|
||||
mtx.vout[0].nValue = burnAmount;
|
||||
mtx.vout[0].scriptPubKey = scriptPubKey;
|
||||
templateMtx.nVersionGroupId = tmpmtx.nVersionGroupId;
|
||||
templateMtx.nVersion = tmpmtx.nVersion;
|
||||
templateMtx.vout.clear();
|
||||
templateMtx.vout.resize(1);
|
||||
|
||||
// not sure we need this now as we create sourcetx ourselves:
|
||||
if (sourcetx.GetHash() != sourcetxid) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// check ac_pubkey:
|
||||
if (CheckVin0PubKey(sourcetx) < 0) {
|
||||
uint8_t evalCode, funcId;
|
||||
int64_t burnAmount;
|
||||
vscript_t vopret;
|
||||
if( !GetOpReturnData(sourceMtx.vout.back().scriptPubKey, vopret) ||
|
||||
!E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> burnAmount)) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof() could not unmarshal source tx opret" << std::endl);
|
||||
return -1;
|
||||
}
|
||||
proof = std::make_pair(sourcetxid, newBranch);
|
||||
templateMtx.vout[0].nValue = burnAmount;
|
||||
templateMtx.vout[0].scriptPubKey = scriptPubKey;
|
||||
|
||||
// not sure we need this now as we create sourcetx ourselves:
|
||||
/*if (sourcetx.GetHash() != sourcetxid) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl);
|
||||
return(-1);
|
||||
}*/
|
||||
|
||||
// check ac_pubkey:
|
||||
if (!CheckVinPubKey(sourceMtx, 0, ASSETCHAINS_OVERRIDE_PUBKEY33)) {
|
||||
return -1;
|
||||
}
|
||||
proofNull = ImportProof(std::make_pair(sourceMtx.GetHash(), newBranch));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -452,71 +352,123 @@ int32_t CheckCODAimport(CTransaction importTx,CTransaction burnTx,std::vector<CT
|
||||
}
|
||||
|
||||
int32_t CheckGATEWAYimport(CTransaction importTx,CTransaction burnTx,std::string refcoin,std::vector<uint8_t> proof,
|
||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub)
|
||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount)
|
||||
{
|
||||
// CTransaction oracletx,regtx; CPubKey regpk;
|
||||
// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts;
|
||||
// std::string name,desc,format; std::vector<CTxOut> vouts;
|
||||
// std::vector<CPubKey> pubkeys; std::vector<uint256>txids;
|
||||
// char markeraddr[64]; int64_t datafee;
|
||||
// std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
CTransaction oracletx,bindtx,regtx; int32_t i,m,n=0,numvouts; uint8_t M,N,taddr,prefix,prefix2,wiftype;
|
||||
uint256 txid,oracletxid,tmporacletxid,merkleroot,mhash,hashBlock;
|
||||
std::string name,desc,format,coin; std::vector<CTxOut> vouts; CPubKey regpk;
|
||||
std::vector<CPubKey> pubkeys,tmppubkeys,tmppublishers; char markeraddr[64],deposit[64],destaddr[64],tmpdest[64]; int64_t datafee;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
|
||||
// ASSETCHAINS_SELFIMPORT is coin
|
||||
if (KOMODO_EARLYTXID!=zeroid && bindtxid!=KOMODO_EARLYTXID)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid import gateway. On this chain only valid import gateway is " << KOMODO_EARLYTXID.GetHex() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
// check for valid burn from external coin blockchain and if valid return(0);
|
||||
// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C')
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// if (name!=refcoin || format!="Ihh")
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// CCtxidaddr(markeraddr,oracletxid);
|
||||
// SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
// for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
// {
|
||||
// txid = it->first.txhash;
|
||||
// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0
|
||||
// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid )
|
||||
// {
|
||||
// pubkeys.push_back(regpk);
|
||||
// n++;
|
||||
// }
|
||||
// }
|
||||
// merkleroot = zeroid;
|
||||
// for (i = m = 0; i < n; i++)
|
||||
// {
|
||||
// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
|
||||
// {
|
||||
// if (merkleroot == zeroid)
|
||||
// merkleroot = mhash, m = 1;
|
||||
// else if (mhash == merkleroot)
|
||||
// m ++;
|
||||
// txids.push_back(txid);
|
||||
// }
|
||||
// }
|
||||
// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
|
||||
// return(-1);
|
||||
// }
|
||||
// proofroot = BitcoinGetProofMerkleRoot(proof, txids);
|
||||
// if (proofroot != merkleroot)
|
||||
// {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
// // check the burntxid is in the proof:
|
||||
// if (std::find(txids.begin(), txids.end(), burnTx.GetHash()) == txids.end()) {
|
||||
// LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid proof for this burntxid=" << burnTx.GetHash().GetHex() << std::endl);
|
||||
// return(-1);
|
||||
// }
|
||||
if (GetTransaction(bindtxid, bindtx, hashBlock, false) == 0 || (numvouts = bindtx.vout.size()) <= 0)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport cant find bindtxid=" << bindtxid.GetHex() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (DecodeImportGatewayBindOpRet(deposit,bindtx.vout[numvouts - 1].scriptPubKey,coin,oracletxid,M,N,tmppubkeys,taddr,prefix,prefix2,wiftype) != 'B')
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid bind tx. bindtxid=" << bindtxid.GetHex() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (refcoin!=coin)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid coin " << refcoin << "!=" << coin << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if ( N == 0 || N > 15 || M > N )
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid N or M " << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (tmppubkeys.size()!=N)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport not enough pubkeys for given N " << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (komodo_txnotarizedconfirmed(bindtxid) == false)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport bindtx not yet confirmed/notarized" << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C')
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (name!=refcoin || format!="Ihh")
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
CCtxidaddr(markeraddr,oracletxid);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0
|
||||
&& DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid )
|
||||
{
|
||||
pubkeys.push_back(regpk);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (pubkeys.size()!=tmppubkeys.size())
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport different number of bind and oracle pubkeys " << tmppubkeys.size() << "!=" << pubkeys.size() << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
merkleroot = zeroid;
|
||||
for (i = m = 0; i < n; i++)
|
||||
{
|
||||
if ((mhash = CCOraclesReverseScan("importgateway-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
|
||||
{
|
||||
if (merkleroot == zeroid)
|
||||
merkleroot = mhash, m = 1;
|
||||
else if (mhash == merkleroot)
|
||||
m ++;
|
||||
tmppublishers.push_back(pubkeys[i]);
|
||||
}
|
||||
}
|
||||
if (publishers.size()!=tmppublishers.size())
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport different number of publishers for burtx in oracle" << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
|
||||
return(-1);
|
||||
}
|
||||
else if ( ImportGatewayVerify(deposit,oracletxid,burnvout,refcoin,burntxid,rawburntx,proof,merkleroot,destpub,taddr,prefix,prefix2) != amount )
|
||||
{
|
||||
CCerror = strprintf("burntxid didnt validate !");
|
||||
LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
else if (importTx.vout[0].nValue!=amount)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport import amount different than in burntx" << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
Getscriptaddress(destaddr,importTx.vout[0].scriptPubKey);
|
||||
Getscriptaddress(tmpdest,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
|
||||
if (strcmp(destaddr,tmpdest)!=0)
|
||||
{
|
||||
LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport import coins destination different than in burntx" << std::endl);
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -545,7 +497,7 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransacti
|
||||
}
|
||||
|
||||
//ac_pubkey check:
|
||||
if (CheckVin0PubKey(sourcetx) < 0) {
|
||||
if (!CheckVinPubKey(sourcetx, 0, ASSETCHAINS_OVERRIDE_PUBKEY33)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -554,9 +506,11 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransacti
|
||||
uint8_t evalCode, funcId;
|
||||
int64_t amount;
|
||||
|
||||
GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret);
|
||||
if (vopret.size() == 0 || !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || evalCode != EVAL_IMPORTCOIN || funcId != 'A') {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
if (!GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret) ||
|
||||
vopret.size() == 0 ||
|
||||
!E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) ||
|
||||
evalCode != EVAL_IMPORTCOIN || funcId != 'A') {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "none or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -571,21 +525,154 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransacti
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* CC Eval method for import coin.
|
||||
*
|
||||
* This method should control every parameter of the ImportCoin transaction, since it has no signature
|
||||
* to protect it from malleability.
|
||||
|
||||
##### 0xffffffff is a special CCid for single chain/dual daemon imports
|
||||
*/
|
||||
bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &importTx,unsigned int nIn)
|
||||
bool CheckMigration(Eval *eval, const CTransaction &importTx, const CTransaction &burnTx, std::vector<CTxOut> & payouts, const ImportProof &proof, const std::vector<uint8_t> &rawproof)
|
||||
{
|
||||
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; uint64_t txfee = 10000; int32_t height,burnvout; std::vector<CPubKey> publishers;
|
||||
uint32_t targetCcid; std::string targetSymbol,srcaddr,destaddr,receipt,rawburntx; uint256 payoutsHash,bindtxid; std::vector<uint8_t> rawproof;
|
||||
std::vector<uint256> txids; CPubKey destpub;
|
||||
vscript_t vimportOpret;
|
||||
if (!GetOpReturnData(importTx.vout.back().scriptPubKey, vimportOpret) ||
|
||||
vimportOpret.empty())
|
||||
return eval->Invalid("invalid-import-tx-no-opret");
|
||||
|
||||
if ( importTx.vout.size() < 2 )
|
||||
|
||||
uint256 tokenid = zeroid;
|
||||
if (vimportOpret.begin()[0] == EVAL_TOKENS) { // for tokens (new opret with tokens)
|
||||
struct CCcontract_info *cpTokens, CCtokens_info;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
uint8_t evalCodeInOpret;
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
vscript_t vnonfungibleOpret;
|
||||
|
||||
cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS);
|
||||
|
||||
if (DecodeTokenOpRet(importTx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) == 0)
|
||||
return eval->Invalid("cannot-decode-import-tx-token-opret");
|
||||
|
||||
uint8_t nonfungibleEvalCode = EVAL_TOKENS; // init to no non-fungibles
|
||||
GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vnonfungibleOpret);
|
||||
if (!vnonfungibleOpret.empty())
|
||||
nonfungibleEvalCode = vnonfungibleOpret.begin()[0];
|
||||
|
||||
// check if burn tx at least has cc evaltoken vins (we cannot get cc input)
|
||||
bool hasTokenVin = false;
|
||||
for (auto vin : burnTx.vin)
|
||||
if (cpTokens->ismyvin(vin.scriptSig))
|
||||
hasTokenVin = true;
|
||||
if (!hasTokenVin)
|
||||
return eval->Invalid("burn-tx-has-no-token-vins");
|
||||
|
||||
// calc outputs for burn tx
|
||||
CAmount ccBurnOutputs = 0;
|
||||
for (auto v : burnTx.vout)
|
||||
if (v.scriptPubKey.IsPayToCryptoCondition() &&
|
||||
CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(nonfungibleEvalCode, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey
|
||||
ccBurnOutputs += v.nValue;
|
||||
|
||||
// calc outputs for import tx
|
||||
CAmount ccImportOutputs = 0;
|
||||
for (auto v : importTx.vout)
|
||||
if (v.scriptPubKey.IsPayToCryptoCondition() &&
|
||||
!IsTokenMarkerVout(v)) // should not be marker here
|
||||
ccImportOutputs += v.nValue;
|
||||
|
||||
if (ccBurnOutputs != ccImportOutputs)
|
||||
return eval->Invalid("token-cc-burned-output-not-equal-cc-imported-output");
|
||||
|
||||
}
|
||||
else if (vimportOpret.begin()[0] != EVAL_IMPORTCOIN) {
|
||||
return eval->Invalid("import-tx-incorrect-opret-eval");
|
||||
}
|
||||
|
||||
// for tokens check burn, import, tokenbase tx
|
||||
if (!tokenid.IsNull()) {
|
||||
|
||||
std::string sourceSymbol;
|
||||
CTransaction tokenbaseTx;
|
||||
if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol; ss >> tokenbaseTx))
|
||||
return eval->Invalid("cannot-unmarshal-rawproof-for-tokens");
|
||||
|
||||
uint256 sourceTokenId;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
uint8_t evalCodeInOpret;
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
if (burnTx.vout.size() > 0 && DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCodeInOpret, sourceTokenId, voutTokenPubkeys, oprets) == 0)
|
||||
return eval->Invalid("cannot-decode-burn-tx-token-opret");
|
||||
|
||||
if (sourceTokenId != tokenbaseTx.GetHash()) // check tokenid in burn tx opret maches the passed tokenbase tx (to prevent cheating by importing user)
|
||||
return eval->Invalid("incorrect-token-creation-tx-passed");
|
||||
|
||||
std::vector<std::pair<uint8_t, vscript_t>> opretsSrc;
|
||||
vscript_t vorigpubkeySrc;
|
||||
std::string nameSrc, descSrc;
|
||||
if (DecodeTokenCreateOpRet(tokenbaseTx.vout.back().scriptPubKey, vorigpubkeySrc, nameSrc, descSrc, opretsSrc) == 0)
|
||||
return eval->Invalid("cannot-decode-token-creation-tx");
|
||||
|
||||
std::vector<std::pair<uint8_t, vscript_t>> opretsImport;
|
||||
vscript_t vorigpubkeyImport;
|
||||
std::string nameImport, descImport;
|
||||
if (importTx.vout.size() == 0 || DecodeTokenCreateOpRet(importTx.vout.back().scriptPubKey, vorigpubkeySrc, nameSrc, descSrc, opretsImport) == 0)
|
||||
return eval->Invalid("cannot-decode-token-import-tx");
|
||||
|
||||
// check that name,pubkey,description in import tx correspond ones in token creation tx in the source chain:
|
||||
if (vorigpubkeySrc != vorigpubkeyImport ||
|
||||
nameSrc != nameImport ||
|
||||
descSrc != descImport)
|
||||
return eval->Invalid("import-tx-token-params-incorrect");
|
||||
}
|
||||
|
||||
|
||||
// Check burntx shows correct outputs hash
|
||||
// if (payoutsHash != SerializeHash(payouts)) // done in ImportCoin
|
||||
// return eval->Invalid("wrong-payouts");
|
||||
|
||||
|
||||
TxProof merkleBranchProof;
|
||||
std::vector<uint256> notaryTxids;
|
||||
|
||||
// Check proof confirms existance of burnTx
|
||||
if (proof.IsMerkleBranch(merkleBranchProof)) {
|
||||
uint256 target = merkleBranchProof.second.Exec(burnTx.GetHash());
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "Eval::ImportCoin() momom target=" << target.GetHex() << " merkleBranchProof.first=" << merkleBranchProof.first.GetHex() << std::endl);
|
||||
if (!CheckMoMoM(merkleBranchProof.first, target)) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MoMoM check failed for importtx=" << importTx.GetHash().GetHex() << std::endl);
|
||||
return eval->Invalid("momom-check-fail");
|
||||
}
|
||||
}
|
||||
else if (proof.IsNotaryTxids(notaryTxids)) {
|
||||
if (!CheckNotariesApproval(burnTx.GetHash(), notaryTxids)) {
|
||||
return eval->Invalid("notaries-approval-check-fail");
|
||||
}
|
||||
}
|
||||
else {
|
||||
return eval->Invalid("invalid-import-proof");
|
||||
}
|
||||
|
||||
/* if (vimportOpret.begin()[0] == EVAL_TOKENS)
|
||||
return eval->Invalid("test-invalid-tokens-are-good!!");
|
||||
else
|
||||
return eval->Invalid("test-invalid-coins-are-good!!"); */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
|
||||
{
|
||||
ImportProof proof;
|
||||
CTransaction burnTx;
|
||||
std::vector<CTxOut> payouts;
|
||||
CAmount txfee = 10000, amount;
|
||||
int32_t height, burnvout;
|
||||
std::vector<CPubKey> publishers;
|
||||
uint32_t targetCcid;
|
||||
std::string targetSymbol, srcaddr, destaddr, receipt, rawburntx;
|
||||
uint256 payoutsHash, bindtxid, burntxid;
|
||||
std::vector<uint8_t> rawproof;
|
||||
std::vector<uint256> txids;
|
||||
CPubKey destpub;
|
||||
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "Validating import tx..., txid=" << importTx.GetHash().GetHex() << std::endl);
|
||||
|
||||
if (strcmp(ASSETCHAINS_SYMBOL, "CFEKDIMXY6") == 0 && chainActive.Height() <= 44693)
|
||||
return true;
|
||||
|
||||
if (importTx.vout.size() < 2)
|
||||
return Invalid("too-few-vouts");
|
||||
// params
|
||||
if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
|
||||
@@ -597,38 +684,47 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
|
||||
// burn params
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof))
|
||||
return Invalid("invalid-burn-tx");
|
||||
// check burn amount
|
||||
{
|
||||
uint64_t burnAmount = burnTx.vout.back().nValue;
|
||||
if (burnAmount == 0)
|
||||
return Invalid("invalid-burn-amount");
|
||||
uint64_t totalOut = 0;
|
||||
for (int i=0; i<importTx.vout.size(); i++)
|
||||
totalOut += importTx.vout[i].nValue;
|
||||
if (totalOut > burnAmount || totalOut < burnAmount-txfee )
|
||||
return Invalid("payout-too-high-or-too-low");
|
||||
}
|
||||
|
||||
if (burnTx.vout.size() == 0)
|
||||
return Invalid("invalid-burn-tx-no-vouts");
|
||||
|
||||
// check burned normal amount >= import amount && burned amount <= import amount + txfee (extra txfee is for miners and relaying, see GetImportCoinValue() func)
|
||||
CAmount burnAmount = burnTx.vout.back().nValue;
|
||||
if (burnAmount == 0)
|
||||
return Invalid("invalid-burn-amount");
|
||||
CAmount totalOut = 0;
|
||||
for (auto v : importTx.vout)
|
||||
if (!v.scriptPubKey.IsPayToCryptoCondition())
|
||||
totalOut += v.nValue;
|
||||
if (totalOut > burnAmount || totalOut < burnAmount - txfee)
|
||||
return Invalid("payout-too-high-or-too-low");
|
||||
|
||||
// Check burntx shows correct outputs hash
|
||||
if (payoutsHash != SerializeHash(payouts))
|
||||
return Invalid("wrong-payouts");
|
||||
if (targetCcid < KOMODO_FIRSTFUNGIBLEID)
|
||||
return Invalid("chain-not-fungible");
|
||||
// Check proof confirms existance of burnTx
|
||||
|
||||
if ( targetCcid != 0xffffffff )
|
||||
{
|
||||
if ( targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol() )
|
||||
|
||||
if (targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol())
|
||||
return Invalid("importcoin-wrong-chain");
|
||||
uint256 target = proof.second.Exec(burnTx.GetHash());
|
||||
if (!CheckMoMoM(proof.first, target))
|
||||
return Invalid("momom-check-fail");
|
||||
|
||||
if (!CheckMigration(this, importTx, burnTx, payouts, proof, rawproof))
|
||||
return false; // eval->Invalid() is called in the func
|
||||
}
|
||||
else
|
||||
{
|
||||
TxProof merkleBranchProof;
|
||||
if (!proof.IsMerkleBranch(merkleBranchProof))
|
||||
return Invalid("invalid-import-proof-for-0xFFFFFFFF");
|
||||
|
||||
if ( targetSymbol == "BEAM" )
|
||||
{
|
||||
if ( ASSETCHAINS_BEAMPORT == 0 )
|
||||
return Invalid("BEAM-import-without-port");
|
||||
else if ( CheckBEAMimport(proof,rawproof,burnTx,payouts) < 0 )
|
||||
else if ( CheckBEAMimport(merkleBranchProof,rawproof,burnTx,payouts) < 0 )
|
||||
return Invalid("BEAM-import-failure");
|
||||
}
|
||||
else if ( targetSymbol == "CODA" )
|
||||
@@ -642,16 +738,20 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
|
||||
{
|
||||
if ( ASSETCHAINS_SELFIMPORT != "PUBKEY" )
|
||||
return Invalid("PUBKEY-import-when-notPUBKEY");
|
||||
else if ( CheckPUBKEYimport(proof,rawproof,burnTx,payouts) < 0 )
|
||||
else if ( CheckPUBKEYimport(merkleBranchProof,rawproof,burnTx,payouts) < 0 )
|
||||
return Invalid("PUBKEY-import-failure");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( targetSymbol != ASSETCHAINS_SELFIMPORT )
|
||||
return Invalid("invalid-gateway-import-coin");
|
||||
else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub) < 0 )
|
||||
else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,burntxid,height,burnvout,rawburntx,destpub,amount)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,burntxid,height,burnvout,rawburntx,destpub,amount) < 0 )
|
||||
return Invalid("GATEWAY-import-failure");
|
||||
}
|
||||
}
|
||||
|
||||
// return Invalid("test-invalid");
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "Valid import tx! txid=" << importTx.GetHash().GetHex() << std::endl);
|
||||
|
||||
return Valid();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#define KMD_TADDR 0
|
||||
#define CC_MARKER_VALUE 10000
|
||||
|
||||
extern uint256 KOMODO_EARLYTXID;
|
||||
|
||||
CScript EncodeImportGatewayBindOpRet(uint8_t funcid,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> importgatewaypubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2,uint8_t wiftype)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY;
|
||||
@@ -212,7 +214,7 @@ int64_t ImportGatewayVerify(char *refburnaddr,uint256 oracletxid,int32_t claimvo
|
||||
}
|
||||
if (std::find(txids.begin(), txids.end(), burntxid) == txids.end())
|
||||
{
|
||||
LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify invalid proof for this burntxid" << std::endl);
|
||||
LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify invalid proof for this burntxid " << burntxid.GetHex() << std::endl);
|
||||
return 0;
|
||||
}
|
||||
if ( DecodeHexTx(tx,deposithex) != 0 )
|
||||
@@ -557,13 +559,19 @@ std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t claimvout,std::string rawburntx,std::vector<uint8_t>proof,CPubKey destpub)
|
||||
std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t claimvout,std::string rawburntx,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()), burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction bindtx; CPubKey mypk; uint256 oracletxid,merkleroot,mhash,hashBlock,txid; std::vector<CTxOut> vouts;
|
||||
int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::string coin; struct CCcontract_info *cp,C;
|
||||
std::vector<CPubKey> pubkeys,publishers; std::vector<uint256> txids; char str[128],burnaddr[64]; int64_t amount;
|
||||
std::vector<CPubKey> pubkeys,publishers; std::vector<uint256> txids; char str[128],burnaddr[64];
|
||||
|
||||
if (KOMODO_EARLYTXID!=zeroid && bindtxid!=KOMODO_EARLYTXID)
|
||||
{
|
||||
CCerror = strprintf("CheckGATEWAYimport invalid import gateway. On this chain only valid import gateway is %s",KOMODO_EARLYTXID.GetHex());
|
||||
LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_IMPORTGATEWAY);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
@@ -572,7 +580,6 @@ std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,
|
||||
{
|
||||
return std::string("");
|
||||
}
|
||||
amount=burntx.vout[0].nValue;
|
||||
LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "ImportGatewayDeposit ht." << height << " " << refcoin << " " << (double)amount/COIN << " numpks." << (int32_t)pubkeys.size() << std::endl);
|
||||
if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 )
|
||||
{
|
||||
@@ -611,18 +618,18 @@ std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,
|
||||
LOGSTREAM("importgateway",CCLOG_INFO, stream << "burntxid." << burntxid.GetHex() << " m." << m << " of n." << n << std::endl);
|
||||
if ( merkleroot == zeroid || m < n/2 )
|
||||
{
|
||||
CCerror = strprintf("couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d",height,coin.c_str(),uint256_str(str,oracletxid),m,n);
|
||||
CCerror = strprintf("couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d",height,refcoin.c_str(),uint256_str(str,oracletxid),m,n);
|
||||
LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl);
|
||||
return("");
|
||||
}
|
||||
if ( ImportGatewayVerify(burnaddr,oracletxid,claimvout,coin,burntxid,rawburntx,proof,merkleroot,destpub,taddr,prefix,prefix2) != amount )
|
||||
if ( ImportGatewayVerify(burnaddr,oracletxid,claimvout,refcoin,burntxid,rawburntx,proof,merkleroot,destpub,taddr,prefix,prefix2) != amount )
|
||||
{
|
||||
CCerror = strprintf("burntxid didnt validate!");
|
||||
LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl);
|
||||
return("");
|
||||
}
|
||||
vouts.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG));
|
||||
burntx.vout.push_back(MakeBurnOutput((CAmount)amount,0xffffffff,refcoin,vouts,proof,bindtxid,publishers,txids,height,claimvout,rawburntx,destpub));
|
||||
burntx.vout.push_back(MakeBurnOutput((CAmount)amount,0xffffffff,refcoin,vouts,proof,bindtxid,publishers,txids,burntxid,height,claimvout,rawburntx,destpub,amount));
|
||||
std::vector<uint256> leaftxids;
|
||||
BitcoinGetProofMerkleRoot(proof, leaftxids);
|
||||
MerkleBranch newBranch(0, leaftxids);
|
||||
|
||||
@@ -197,7 +197,7 @@ int64_t OracleCurrentDatafee(uint256 reforacletxid,char *markeraddr,CPubKey publ
|
||||
{
|
||||
uint256 txid,oracletxid,hashBlock; int64_t datafee=0,dfee; int32_t dheight=0,vout,height,numvouts; CTransaction tx; CPubKey pk;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -306,7 +306,7 @@ uint256 OraclesBatontxid(uint256 reforacletxid,CPubKey refpk)
|
||||
batontxid = zeroid;
|
||||
cp = CCinit(&C,EVAL_ORACLES);
|
||||
CCtxidaddr(markeraddr,reforacletxid);
|
||||
SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
//char str[67]; fprintf(stderr,"markeraddr.(%s) %s\n",markeraddr,pubkey33_str(str,(uint8_t *)&refpk));
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
@@ -532,7 +532,7 @@ int32_t oracleprice_add(std::vector<struct oracleprice_info> &publishers,CPubKey
|
||||
if ( format[0] != 'L' )
|
||||
return(0);
|
||||
cp = CCinit(&C,EVAL_ORACLES);
|
||||
SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -992,7 +992,7 @@ UniValue OracleInfo(uint256 origtxid)
|
||||
result.push_back(Pair("description",description));
|
||||
result.push_back(Pair("format",format));
|
||||
result.push_back(Pair("marker",markeraddr));
|
||||
SetCCunspents(unspentOutputs,markeraddr,true);
|
||||
SetCCunspents(unspentOutputs,markeraddr,false);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
@@ -1028,7 +1028,7 @@ UniValue OraclesList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65];
|
||||
cp = CCinit(&C,EVAL_ORACLES);
|
||||
SetCCtxids(addressIndex,cp->normaladdr,true);
|
||||
SetCCtxids(addressIndex,cp->normaladdr,false);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
#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
|
||||
|
||||
@@ -193,11 +199,10 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
{
|
||||
if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
|
||||
return(eval->Invalid("negative values"));
|
||||
if ( !CheckTxFee(tx, PAYMENTS_TXFEE, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) )
|
||||
return eval->Invalid("txfee is too high");
|
||||
Paymentspk = GetUnspendable(cp,0);
|
||||
//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");
|
||||
// Get all the script pubkeys and allocations
|
||||
std::vector<int64_t> allocations;
|
||||
std::vector<CScript> scriptPubKeys;
|
||||
@@ -212,6 +217,20 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
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() )
|
||||
{
|
||||
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++;
|
||||
}
|
||||
@@ -247,7 +266,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
int64_t test = allocations[n];
|
||||
test *= checkamount;
|
||||
test /= totalallocations;
|
||||
if ( test != tx.vout[i].nValue )
|
||||
if ( test != tx.vout[i].nValue && 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"));
|
||||
@@ -277,18 +296,28 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey);
|
||||
if ( strcmp(destaddr,coinaddr) != 0 )
|
||||
{
|
||||
std::vector<uint8_t> scriptPubKey,opret; uint256 checktxid;
|
||||
if ( txin.vout.size() < 2 || DecodePaymentsFundOpRet(txin.vout[txin.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid )
|
||||
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);
|
||||
}
|
||||
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?
|
||||
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());
|
||||
return(eval->Invalid("vin is not paymentsCC type"));
|
||||
} //else fprintf(stderr, "vin.%i opret type txid.%s\n", i, txin.GetHash().ToString().c_str());
|
||||
}
|
||||
}
|
||||
// check the chain depth vs locked blcoks requirement.
|
||||
CBlockIndex* pblockindex = mapBlockIndex[blockhash];
|
||||
if ( pblockindex->GetHeight() > ht-lockedblocks )
|
||||
// check the chain depth vs locked blocks requirement.
|
||||
CBlockIndex* pblockindex = komodo_blockindex(blockhash);
|
||||
if ( pblockindex == 0 || pblockindex->GetHeight() > ht-lockedblocks )
|
||||
{
|
||||
fprintf(stderr, "vin.%i is not elegible to be spent yet height.%i vs elegible_ht.%i\n", i, pblockindex->GetHeight(), ht-lockedblocks);
|
||||
fprintf(stderr, "vin.%i is not elegible to be spent yet height.%i vs elegible_ht.%i\n", i, pblockindex!=0?pblockindex->GetHeight():0, ht-lockedblocks);
|
||||
return(eval->Invalid("vin not elegible"));
|
||||
}
|
||||
} else return(eval->Invalid("cant get vin transaction"));
|
||||
@@ -340,8 +369,18 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
|
||||
}
|
||||
if ( iter == 0 )
|
||||
{
|
||||
std::vector<uint8_t> scriptPubKey,opret;
|
||||
if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() < 2 || DecodePaymentsFundOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid )
|
||||
CScript opret; uint256 checktxid; int32_t opret_ind;
|
||||
if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 )
|
||||
{
|
||||
// get op_return from CCvout
|
||||
opret = getCCopret(vintx.vout[0].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 )
|
||||
{
|
||||
fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str());
|
||||
continue;
|
||||
@@ -524,7 +563,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
|
||||
newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue);
|
||||
mtx.vout[i+1].nValue = PAYMENTS_TXFEE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE )
|
||||
{
|
||||
std::string rawtx;
|
||||
@@ -603,10 +642,16 @@ 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>>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret);
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript());
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(payments_rawtxresult(result,rawtx,1));
|
||||
@@ -630,24 +675,34 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
|
||||
UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); CPubKey mypk; std::string rawtx;
|
||||
std::vector<uint8_t> scriptPubKey,opret; int32_t allocation,n,retval0,retval1=0;
|
||||
std::vector<uint8_t> scriptPubKey,opret; int32_t n,retval0,retval1=0; int64_t allocation;
|
||||
cJSON *params = payments_reparse(&n,jsonstr);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( params != 0 && n > 1 && n <= 3 )
|
||||
{
|
||||
allocation = juint(jitem(params,0),0);
|
||||
allocation = (int64_t)jint(jitem(params,0),0);
|
||||
retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0);
|
||||
if ( n == 3 )
|
||||
retval1 = payments_parsehexdata(opret,jitem(params,2),0);
|
||||
if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE,10) > 0 )
|
||||
CScript test = CScript(scriptPubKey.begin(),scriptPubKey.end());
|
||||
txnouttype whichType;
|
||||
if (!::IsStandard(test, whichType))
|
||||
{
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(payments_rawtxresult(result,rawtx,1));
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","scriptPubkey is not valid payment."));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( n == 3 )
|
||||
retval1 = payments_parsehexdata(opret,jitem(params,2),0);
|
||||
if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE*2,10) > 0 )
|
||||
{
|
||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret));
|
||||
if ( params != 0 )
|
||||
free_json(params);
|
||||
return(payments_rawtxresult(result,rawtx,1));
|
||||
}
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid params or cant find txfee"));
|
||||
}
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","invalid params or cant find txfee"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -867,7 +922,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
|
||||
funds = CCaddress_balance(fundsaddr,1);
|
||||
result.push_back(Pair(fundsaddr,ValueFromAmount(funds)));
|
||||
GetCCaddress(cp,fundsopretaddr,Paymentspk);
|
||||
fundsopret = CCaddress_balance(fundsopretaddr,1);
|
||||
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"));
|
||||
|
||||
@@ -320,8 +320,7 @@ int32_t prices_syntheticvec(std::vector<uint16_t> &vec,std::vector<std::string>
|
||||
|
||||
int64_t prices_syntheticprice(std::vector<uint16_t> vec,int32_t height,int32_t minmax,int16_t leverage)
|
||||
{
|
||||
int32_t i,ind,errcode,depth,retval = -1; uint16_t opcode; int64_t *pricedata,pricestack[4],price,den,a,b,c;
|
||||
pricedata = (int64_t *)calloc(sizeof(*pricedata)*3,1 + PRICES_DAYWINDOW*2 + PRICES_SMOOTHWIDTH);
|
||||
int32_t i,ind,errcode,depth,retval = -1; uint16_t opcode; int64_t pricedata[PRICES_MAXDATAPOINTS],pricestack[4],price,den,a,b,c;
|
||||
price = den = depth = errcode = 0;
|
||||
for (i=0; i<vec.size(); i++)
|
||||
{
|
||||
@@ -331,7 +330,7 @@ int64_t prices_syntheticprice(std::vector<uint16_t> vec,int32_t height,int32_t m
|
||||
{
|
||||
case 0:
|
||||
pricestack[depth] = 0;
|
||||
if ( prices_extract(pricedata,height,1,ind) == 0 )
|
||||
if ( komodo_priceget(pricedata,ind,height,1) > 0 )
|
||||
{
|
||||
if ( minmax == 0 )
|
||||
pricestack[depth] = pricedata[2];
|
||||
@@ -420,7 +419,6 @@ int64_t prices_syntheticprice(std::vector<uint16_t> vec,int32_t height,int32_t m
|
||||
if ( errcode != 0 )
|
||||
break;
|
||||
}
|
||||
free(pricedata);
|
||||
if ( den == 0 )
|
||||
return(-11);
|
||||
else if ( depth != 0 )
|
||||
|
||||
@@ -92,6 +92,7 @@ static CBlock CreateGenesisBlock(uint32_t nTime, const uint256& nNonce, const st
|
||||
void *chainparams_commandline(void *ptr);
|
||||
#include "komodo_defs.h"
|
||||
int32_t ASSETCHAINS_BLOCKTIME = 60;
|
||||
uint64_t ASSETCHAINS_NK[2];
|
||||
|
||||
const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
|
||||
|
||||
@@ -282,6 +283,14 @@ void *chainparams_commandline(void *ptr)
|
||||
mainParams.consensus.nPowTargetSpacing = ASSETCHAINS_BLOCKTIME;
|
||||
}
|
||||
mainParams.SetDefaultPort(ASSETCHAINS_P2PPORT);
|
||||
if ( ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0 )
|
||||
{
|
||||
//BOOST_STATIC_ASSERT(equihash_parameters_acceptable(ASSETCHAINS_NK[0], ASSETCHAINS_NK[1]));
|
||||
mainParams.SetNValue(ASSETCHAINS_NK[0]);
|
||||
mainParams.SetKValue(ASSETCHAINS_NK[1]);
|
||||
}
|
||||
if ( KOMODO_TESTNODE != 0 )
|
||||
mainParams.SetMiningRequiresPeers(false);
|
||||
if ( ASSETCHAINS_RPCPORT == 0 )
|
||||
ASSETCHAINS_RPCPORT = ASSETCHAINS_P2PPORT + 1;
|
||||
mainParams.pchMessageStart[0] = ASSETCHAINS_MAGIC & 0xff;
|
||||
|
||||
@@ -119,6 +119,9 @@ public:
|
||||
|
||||
void SetDefaultPort(uint16_t port) { nDefaultPort = port; }
|
||||
void SetCheckpointData(CCheckpointData checkpointData);
|
||||
void SetNValue(uint64_t n) { nEquihashN = n; }
|
||||
void SetKValue(uint64_t k) { nEquihashK = k; }
|
||||
void SetMiningRequiresPeers(bool flag) { fMiningRequiresPeers = flag; }
|
||||
|
||||
//void setnonce(uint32_t nonce) { memcpy(&genesis.nNonce,&nonce,sizeof(nonce)); }
|
||||
//void settimestamp(uint32_t timestamp) { genesis.nTime = timestamp; }
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#include "importcoin.h"
|
||||
#include "main.h"
|
||||
#include "notarisationdb.h"
|
||||
#include "merkleblock.h"
|
||||
|
||||
#include "cc/CCinclude.h"
|
||||
|
||||
/*
|
||||
* The crosschain workflow.
|
||||
@@ -64,11 +67,12 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh
|
||||
if (kmdHeight < 0 || kmdHeight > chainActive.Height())
|
||||
return uint256();
|
||||
|
||||
int seenOwnNotarisations = 0;
|
||||
int seenOwnNotarisations = 0, i = 0;
|
||||
|
||||
int authority = GetSymbolAuthority(symbol);
|
||||
std::set<uint256> tmp_moms;
|
||||
|
||||
for (int i=0; i<NOTARISATION_SCAN_LIMIT_BLOCKS; i++) {
|
||||
for (i=0; i<NOTARISATION_SCAN_LIMIT_BLOCKS; i++) {
|
||||
if (i > kmdHeight) break;
|
||||
NotarisationsInBlock notarisations;
|
||||
uint256 blockHash = *chainActive[kmdHeight-i]->phashBlock;
|
||||
@@ -82,17 +86,17 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh
|
||||
seenOwnNotarisations++;
|
||||
if (seenOwnNotarisations == 1)
|
||||
destNotarisationTxid = nota.first;
|
||||
else if (seenOwnNotarisations == 2)
|
||||
else if (seenOwnNotarisations == 7)
|
||||
goto end;
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
||||
if (seenOwnNotarisations == 1) {
|
||||
if (seenOwnNotarisations >= 1) {
|
||||
BOOST_FOREACH(Notarisation& nota, notarisations) {
|
||||
if (GetSymbolAuthority(nota.second.symbol) == authority)
|
||||
if (nota.second.ccId == targetCCid) {
|
||||
moms.push_back(nota.second.MoM);
|
||||
tmp_moms.insert(nota.second.MoM);
|
||||
//fprintf(stderr, "added mom: %s\n",nota.second.MoM.GetHex().data());
|
||||
}
|
||||
}
|
||||
@@ -105,6 +109,10 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh
|
||||
return uint256();
|
||||
|
||||
end:
|
||||
// add set to vector. Set makes sure there are no dupes included.
|
||||
moms.clear();
|
||||
std::copy(tmp_moms.begin(), tmp_moms.end(), std::back_inserter(moms));
|
||||
//fprintf(stderr, "SeenOwnNotarisations.%i moms.size.%li blocks scanned.%i\n",seenOwnNotarisations, moms.size(), i);
|
||||
return GetMerkleRoot(moms);
|
||||
}
|
||||
|
||||
@@ -138,7 +146,7 @@ int ScanNotarisationsFromHeight(int nHeight, const IsTarget f, Notarisation &fou
|
||||
|
||||
/* On KMD */
|
||||
TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
|
||||
const TxProof assetChainProof)
|
||||
const TxProof assetChainProof, int32_t offset)
|
||||
{
|
||||
/*
|
||||
* Here we are given a proof generated by an assetchain A which goes from given txid to
|
||||
@@ -173,6 +181,9 @@ TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_
|
||||
kmdHeight = ScanNotarisationsFromHeight(kmdHeight, isTarget, nota);
|
||||
if (!kmdHeight)
|
||||
throw std::runtime_error("Cannot find notarisation for target inclusive of source");
|
||||
|
||||
if ( offset != 0 )
|
||||
kmdHeight += offset;
|
||||
|
||||
// Get MoMs for kmd height and symbol
|
||||
std::vector<uint256> moms;
|
||||
@@ -219,24 +230,27 @@ cont:
|
||||
* Takes an importTx that has proof leading to assetchain root
|
||||
* and extends proof to cross chain root
|
||||
*/
|
||||
void CompleteImportTransaction(CTransaction &importTx)
|
||||
void CompleteImportTransaction(CTransaction &importTx, int32_t offset)
|
||||
{
|
||||
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; std::vector<uint8_t> rawproof;
|
||||
ImportProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; std::vector<uint8_t> rawproof;
|
||||
if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
|
||||
throw std::runtime_error("Couldn't parse importTx");
|
||||
throw std::runtime_error("Couldn't unmarshal importTx");
|
||||
|
||||
std::string targetSymbol;
|
||||
uint32_t targetCCid;
|
||||
uint256 payoutsHash;
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof))
|
||||
throw std::runtime_error("Couldn't parse burnTx");
|
||||
throw std::runtime_error("Couldn't unmarshal burnTx");
|
||||
|
||||
proof = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, proof);
|
||||
TxProof merkleBranch;
|
||||
if( !proof.IsMerkleBranch(merkleBranch) )
|
||||
throw std::runtime_error("Incorrect import tx proof");
|
||||
TxProof newMerkleBranch = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, merkleBranch, offset);
|
||||
ImportProof newProof(newMerkleBranch);
|
||||
|
||||
importTx = MakeImportCoinTransaction(proof, burnTx, payouts);
|
||||
importTx = MakeImportCoinTransaction(newProof, burnTx, payouts);
|
||||
}
|
||||
|
||||
|
||||
bool IsSameAssetChain(const Notarisation ¬a) {
|
||||
return strcmp(nota.second.symbol, ASSETCHAINS_SYMBOL) == 0;
|
||||
};
|
||||
@@ -298,6 +312,111 @@ bool CheckMoMoM(uint256 kmdNotarisationHash, uint256 momom)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Check notaries approvals for the txoutproofs of burn tx
|
||||
* (alternate check if MoMoM check has failed)
|
||||
* Params:
|
||||
* burntxid - txid of burn tx on the source chain
|
||||
* rawproof - array of txids of notaries' proofs
|
||||
*/
|
||||
bool CheckNotariesApproval(uint256 burntxid, const std::vector<uint256> & notaryTxids)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
// get notaries:
|
||||
uint8_t notaries_pubkeys[64][33];
|
||||
std::vector< std::vector<uint8_t> > alreadySigned;
|
||||
|
||||
//unmarshal notaries approval txids
|
||||
for(auto notarytxid : notaryTxids ) {
|
||||
EvalRef eval;
|
||||
CBlockIndex block;
|
||||
CTransaction notarytx; // tx with notary approval of txproof existence
|
||||
|
||||
// get notary approval tx
|
||||
if (eval->GetTxConfirmed(notarytxid, notarytx, block)) {
|
||||
|
||||
std::vector<uint8_t> vopret;
|
||||
if (!notarytx.vout.empty() && GetOpReturnData(notarytx.vout.back().scriptPubKey, vopret)) {
|
||||
std::vector<uint8_t> txoutproof;
|
||||
|
||||
if (E_UNMARSHAL(vopret, ss >> txoutproof)) {
|
||||
CMerkleBlock merkleBlock;
|
||||
std::vector<uint256> prooftxids;
|
||||
// extract block's merkle tree
|
||||
if (E_UNMARSHAL(txoutproof, ss >> merkleBlock)) {
|
||||
|
||||
// extract proven txids:
|
||||
merkleBlock.txn.ExtractMatches(prooftxids);
|
||||
if (merkleBlock.txn.ExtractMatches(prooftxids) != merkleBlock.header.hashMerkleRoot || // check block merkle root is correct
|
||||
std::find(prooftxids.begin(), prooftxids.end(), burntxid) != prooftxids.end()) { // check burn txid is in proven txids list
|
||||
|
||||
if (komodo_notaries(notaries_pubkeys, block.GetHeight(), block.GetBlockTime()) >= 0) {
|
||||
// check it is a notary who signed approved tx:
|
||||
int i;
|
||||
for (i = 0; i < sizeof(notaries_pubkeys) / sizeof(notaries_pubkeys[0]); i++) {
|
||||
std::vector<uint8_t> vnotarypubkey(notaries_pubkeys[i], notaries_pubkeys[i] + 33);
|
||||
#ifdef TESTMODE
|
||||
char test_notary_pubkey_hex[] = "029fa302968bbae81f41983d2ec20445557b889d31227caec5d910d19b7510ef86";
|
||||
uint8_t test_notary_pubkey33[33];
|
||||
decode_hex(test_notary_pubkey33, 33, test_notary_pubkey_hex);
|
||||
#endif
|
||||
if (CheckVinPubKey(notarytx, 0, notaries_pubkeys[i]) // is signed by a notary?
|
||||
&& std::find(alreadySigned.begin(), alreadySigned.end(), vnotarypubkey) == alreadySigned.end() // check if notary not re-used
|
||||
#ifdef TESTMODE
|
||||
|| CheckVinPubKey(notarytx, 0, test_notary_pubkey33) // test
|
||||
#endif
|
||||
)
|
||||
{
|
||||
alreadySigned.push_back(vnotarypubkey);
|
||||
count++;
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "CheckNotariesApproval() notary approval checked, count=" << count << std::endl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == sizeof(notaries_pubkeys) / sizeof(notaries_pubkeys[0]))
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "CheckNotariesApproval() txproof not signed by a notary or reused" << std::endl);
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() cannot get current notaries pubkeys" << std::endl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() burntxid not found in txoutproof or incorrect txoutproof" << std::endl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not unmarshal merkleBlock" << std::endl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not unmarshal txoutproof" << std::endl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() no opret in the notary tx" << std::endl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not load notary tx" << std::endl);
|
||||
}
|
||||
}
|
||||
|
||||
bool retcode;
|
||||
#ifdef TESTMODE
|
||||
if (count < 1) { // 1 for test
|
||||
#else
|
||||
if (count < 5) {
|
||||
#endif
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() not enough signed notary transactions=" << count << std::endl);
|
||||
retcode = false;
|
||||
}
|
||||
else
|
||||
retcode = true;
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* On assetchain
|
||||
|
||||
@@ -38,11 +38,11 @@ TxProof GetAssetchainProof(uint256 hash,CTransaction burnTx);
|
||||
uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeight,
|
||||
std::vector<uint256> &moms, uint256 &destNotarisationTxid);
|
||||
TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
|
||||
const TxProof assetChainProof);
|
||||
void CompleteImportTransaction(CTransaction &importTx);
|
||||
const TxProof assetChainProof,int32_t offset);
|
||||
void CompleteImportTransaction(CTransaction &importTx,int32_t offset);
|
||||
|
||||
/* On assetchain */
|
||||
bool CheckMoMoM(uint256 kmdNotarisationHash, uint256 momom);
|
||||
|
||||
bool CheckNotariesApproval(uint256 burntxid, const std::vector<uint256> & notaryTxids);
|
||||
|
||||
#endif /* CROSSCHAIN_H */
|
||||
|
||||
@@ -54,33 +54,84 @@
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#endif
|
||||
*/
|
||||
|
||||
static EhSolverCancelledException solver_cancelled;
|
||||
|
||||
int8_t ZeroizeUnusedBits(size_t N, unsigned char* hash, size_t hLen)
|
||||
{
|
||||
uint8_t rem = N % 8;
|
||||
if (rem)
|
||||
{
|
||||
// clear lowest 8-rem bits
|
||||
const size_t step = GetSizeInBytes(N);
|
||||
for (size_t i = step - 1; i < hLen; i += step)
|
||||
{
|
||||
uint8_t b = 0xff << (8-rem);
|
||||
hash[i] &= b;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
int Equihash<N,K>::InitialiseState(eh_HashState& base_state)
|
||||
{
|
||||
uint32_t le_N = htole32(N);
|
||||
uint32_t le_K = htole32(K);
|
||||
|
||||
unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] = {};
|
||||
memcpy(personalization, "ZcashPoW", 8);
|
||||
if ( ASSETCHAINS_NK[0] == 0 && ASSETCHAINS_NK[1] == 0 )
|
||||
memcpy(personalization, "ZcashPoW", 8);
|
||||
else
|
||||
memcpy(personalization, "NandKPoW", 8);
|
||||
memcpy(personalization+8, &le_N, 4);
|
||||
memcpy(personalization+12, &le_K, 4);
|
||||
|
||||
const uint8_t outlen = (512 / N) * GetSizeInBytes(N);
|
||||
|
||||
BOOST_STATIC_ASSERT(!((!outlen) || (outlen > BLAKE2B_OUTBYTES)));
|
||||
return crypto_generichash_blake2b_init_salt_personal(&base_state,
|
||||
NULL, 0, // No key.
|
||||
(512/N)*N/8,
|
||||
outlen,
|
||||
NULL, // No salt.
|
||||
personalization);
|
||||
}
|
||||
|
||||
void GenerateHash(const eh_HashState& base_state, eh_index g,
|
||||
unsigned char* hash, size_t hLen)
|
||||
unsigned char* hash, size_t hLen, size_t N)
|
||||
{
|
||||
eh_HashState state;
|
||||
state = base_state;
|
||||
eh_index lei = htole32(g);
|
||||
crypto_generichash_blake2b_update(&state, (const unsigned char*) &lei,
|
||||
sizeof(eh_index));
|
||||
crypto_generichash_blake2b_final(&state, hash, hLen);
|
||||
if ( ASSETCHAINS_NK[0] == 0 && ASSETCHAINS_NK[1] == 0 )
|
||||
{
|
||||
eh_HashState state;
|
||||
state = base_state;
|
||||
eh_index lei = htole32(g);
|
||||
crypto_generichash_blake2b_update(&state, (const unsigned char*) &lei,
|
||||
sizeof(eh_index));
|
||||
crypto_generichash_blake2b_final(&state, hash, hLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t myHash[16] = {0};
|
||||
uint32_t startIndex = g & 0xFFFFFFF0;
|
||||
|
||||
for (uint32_t g2 = startIndex; g2 <= g; g2++) {
|
||||
uint32_t tmpHash[16] = {0};
|
||||
|
||||
eh_HashState state;
|
||||
state = base_state;
|
||||
eh_index lei = htole32(g2);
|
||||
crypto_generichash_blake2b_update(&state, (const unsigned char*) &lei,
|
||||
sizeof(eh_index));
|
||||
|
||||
crypto_generichash_blake2b_final(&state, (unsigned char*)&tmpHash[0], static_cast<uint8_t>(hLen));
|
||||
|
||||
for (uint32_t idx = 0; idx < 16; idx++) myHash[idx] += tmpHash[idx];
|
||||
}
|
||||
|
||||
memcpy(hash, &myHash[0], hLen);
|
||||
ZeroizeUnusedBits(N, hash, hLen);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpandArray(const unsigned char* in, size_t in_len,
|
||||
@@ -88,7 +139,7 @@ void ExpandArray(const unsigned char* in, size_t in_len,
|
||||
size_t bit_len, size_t byte_pad)
|
||||
{
|
||||
assert(bit_len >= 8);
|
||||
assert(8*sizeof(uint32_t) >= 7+bit_len);
|
||||
assert(8*sizeof(uint32_t) >= bit_len);
|
||||
|
||||
size_t out_width { (bit_len+7)/8 + byte_pad };
|
||||
assert(out_len == 8*out_width*in_len/bit_len);
|
||||
@@ -131,10 +182,10 @@ void CompressArray(const unsigned char* in, size_t in_len,
|
||||
size_t bit_len, size_t byte_pad)
|
||||
{
|
||||
assert(bit_len >= 8);
|
||||
assert(8*sizeof(uint32_t) >= 7+bit_len);
|
||||
assert(8*sizeof(uint32_t) >= bit_len);
|
||||
|
||||
size_t in_width { (bit_len+7)/8 + byte_pad };
|
||||
assert(out_len == bit_len*in_len/(8*in_width));
|
||||
assert(out_len == (bit_len*in_len/in_width + 7)/8);
|
||||
|
||||
uint32_t bit_len_mask { ((uint32_t)1 << bit_len) - 1 };
|
||||
|
||||
@@ -148,17 +199,23 @@ void CompressArray(const unsigned char* in, size_t in_len,
|
||||
// When we have fewer than 8 bits left in the accumulator, read the next
|
||||
// input element.
|
||||
if (acc_bits < 8) {
|
||||
if (j < in_len) {
|
||||
acc_value = acc_value << bit_len;
|
||||
for (size_t x = byte_pad; x < in_width; x++) {
|
||||
acc_value = acc_value | (
|
||||
(
|
||||
// Apply bit_len_mask across byte boundaries
|
||||
in[j+x] & ((bit_len_mask >> (8*(in_width-x-1))) & 0xFF)
|
||||
) << (8*(in_width-x-1))); // Big-endian
|
||||
in[j + x] & ((bit_len_mask >> (8 * (in_width - x - 1))) & 0xFF)
|
||||
) << (8 * (in_width - x - 1))); // Big-endian
|
||||
}
|
||||
j += in_width;
|
||||
acc_bits += bit_len;
|
||||
}
|
||||
else {
|
||||
acc_value <<= 8 - acc_bits;
|
||||
acc_bits += 8 - acc_bits;;
|
||||
}
|
||||
}
|
||||
|
||||
acc_bits -= 8;
|
||||
out[i] = (acc_value >> acc_bits) & 0xFF;
|
||||
@@ -207,7 +264,7 @@ std::vector<eh_index> GetIndicesFromMinimal(std::vector<unsigned char> minimal,
|
||||
ExpandArray(minimal.data(), minimal.size(),
|
||||
array.data(), lenIndices, cBitLen+1, bytePad);
|
||||
std::vector<eh_index> ret;
|
||||
for (int i = 0; i < lenIndices; i += sizeof(eh_index)) {
|
||||
for (size_t i = 0; i < lenIndices; i += sizeof(eh_index)) {
|
||||
ret.push_back(ArrayToEhIndex(array.data()+i));
|
||||
}
|
||||
return ret;
|
||||
@@ -221,7 +278,7 @@ std::vector<unsigned char> GetMinimalFromIndices(std::vector<eh_index> indices,
|
||||
size_t minLen { (cBitLen+1)*lenIndices/(8*sizeof(eh_index)) };
|
||||
size_t bytePad { sizeof(eh_index) - ((cBitLen+1)+7)/8 };
|
||||
std::vector<unsigned char> array(lenIndices);
|
||||
for (int i = 0; i < indices.size(); i++) {
|
||||
for (size_t i = 0; i < indices.size(); i++) {
|
||||
EhIndexToArray(indices[i], array.data()+(i*sizeof(eh_index)));
|
||||
}
|
||||
std::vector<unsigned char> ret(minLen);
|
||||
@@ -254,12 +311,12 @@ FullStepRow<WIDTH>::FullStepRow(const unsigned char* hashIn, size_t hInLen,
|
||||
}
|
||||
|
||||
template<size_t WIDTH> template<size_t W>
|
||||
FullStepRow<WIDTH>::FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, int trim) :
|
||||
FullStepRow<WIDTH>::FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, size_t trim) :
|
||||
StepRow<WIDTH> {a}
|
||||
{
|
||||
assert(len+lenIndices <= W);
|
||||
assert(len-trim+(2*lenIndices) <= WIDTH);
|
||||
for (int i = trim; i < len; i++)
|
||||
for (size_t i = trim; i < len; i++)
|
||||
hash[i-trim] = a.hash[i] ^ b.hash[i];
|
||||
if (a.IndicesBefore(b, len, lenIndices)) {
|
||||
std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim);
|
||||
@@ -281,7 +338,7 @@ template<size_t WIDTH>
|
||||
bool StepRow<WIDTH>::IsZero(size_t len)
|
||||
{
|
||||
// This doesn't need to be constant time.
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (hash[i] != 0)
|
||||
return false;
|
||||
}
|
||||
@@ -301,10 +358,10 @@ std::vector<unsigned char> FullStepRow<WIDTH>::GetIndices(size_t len, size_t len
|
||||
}
|
||||
|
||||
template<size_t WIDTH>
|
||||
bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, int l)
|
||||
bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, size_t l)
|
||||
{
|
||||
// This doesn't need to be constant time.
|
||||
for (int j = 0; j < l; j++) {
|
||||
for (size_t j = 0; j < l; j++) {
|
||||
if (a.hash[j] != b.hash[j])
|
||||
return false;
|
||||
}
|
||||
@@ -326,7 +383,7 @@ TruncatedStepRow<WIDTH>::TruncatedStepRow(const TruncatedStepRow<W>& a, const Tr
|
||||
{
|
||||
assert(len+lenIndices <= W);
|
||||
assert(len-trim+(2*lenIndices) <= WIDTH);
|
||||
for (int i = trim; i < len; i++)
|
||||
for (size_t i = static_cast<size_t>(trim); i < len; i++)
|
||||
hash[i-trim] = a.hash[i] ^ b.hash[i];
|
||||
if (a.IndicesBefore(b, len, lenIndices)) {
|
||||
std::copy(a.hash+len, a.hash+len+lenIndices, hash+len-trim);
|
||||
@@ -355,10 +412,10 @@ std::shared_ptr<eh_trunc> TruncatedStepRow<WIDTH>::GetTruncatedIndices(size_t le
|
||||
#ifdef ENABLE_MINING
|
||||
template<unsigned int N, unsigned int K>
|
||||
bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
eh_index init_size { 1U << (CollisionBitLength + 1) };
|
||||
|
||||
// 1) Generate first list
|
||||
LogPrint("pow", "Generating first list\n");
|
||||
@@ -368,16 +425,16 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
||||
X.reserve(init_size);
|
||||
unsigned char tmpHash[HashOutput];
|
||||
for (eh_index g = 0; X.size() < init_size; g++) {
|
||||
GenerateHash(base_state, g, tmpHash, HashOutput);
|
||||
GenerateHash(base_state, g, tmpHash, HashOutput, N);
|
||||
for (eh_index i = 0; i < IndicesPerHashOutput && X.size() < init_size; i++) {
|
||||
X.emplace_back(tmpHash+(i*N/8), N/8, HashLength,
|
||||
CollisionBitLength, (g*IndicesPerHashOutput)+i);
|
||||
X.emplace_back(tmpHash+(i*GetSizeInBytes(N)), GetSizeInBytes(N), HashLength,
|
||||
CollisionBitLength, static_cast<int>(g*IndicesPerHashOutput)+i);
|
||||
}
|
||||
if (cancelled(ListGeneration)) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
||||
for (int r = 1; r < K && X.size() > 0; r++) {
|
||||
for (unsigned int r = 1; r < K && X.size() > 0; r++) {
|
||||
LogPrint("pow", "Round %d:\n", r);
|
||||
// 2a) Sort the list
|
||||
LogPrint("pow", "- Sorting list\n");
|
||||
@@ -385,20 +442,20 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
||||
if (cancelled(ListSorting)) throw solver_cancelled;
|
||||
|
||||
LogPrint("pow", "- Finding collisions\n");
|
||||
int i = 0;
|
||||
int posFree = 0;
|
||||
size_t i = 0;
|
||||
size_t posFree = 0;
|
||||
std::vector<FullStepRow<FullWidth>> Xc;
|
||||
while (i < X.size() - 1) {
|
||||
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
||||
int j = 1;
|
||||
size_t j = 1;
|
||||
while (i+j < X.size() &&
|
||||
HasCollision(X[i], X[i+j], CollisionByteLength)) {
|
||||
j++;
|
||||
}
|
||||
|
||||
// 2c) Calculate tuples (X_i ^ X_j, (i, j))
|
||||
for (int l = 0; l < j - 1; l++) {
|
||||
for (int m = l + 1; m < j; m++) {
|
||||
for (size_t l = 0; l < j - 1; l++) {
|
||||
for (size_t m = l + 1; m < j; m++) {
|
||||
if (DistinctIndices(X[i+l], X[i+m], hashLen, lenIndices)) {
|
||||
Xc.emplace_back(X[i+l], X[i+m], hashLen, lenIndices, CollisionByteLength);
|
||||
}
|
||||
@@ -442,16 +499,16 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
||||
std::sort(X.begin(), X.end(), CompareSR(hashLen));
|
||||
if (cancelled(FinalSorting)) throw solver_cancelled;
|
||||
LogPrint("pow", "- Finding collisions\n");
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
while (i < X.size() - 1) {
|
||||
int j = 1;
|
||||
size_t j = 1;
|
||||
while (i+j < X.size() &&
|
||||
HasCollision(X[i], X[i+j], hashLen)) {
|
||||
j++;
|
||||
}
|
||||
|
||||
for (int l = 0; l < j - 1; l++) {
|
||||
for (int m = l + 1; m < j; m++) {
|
||||
for (size_t l = 0; l < j - 1; l++) {
|
||||
for (size_t m = l + 1; m < j; m++) {
|
||||
FullStepRow<FinalFullWidth> res(X[i+l], X[i+m], hashLen, lenIndices, 0);
|
||||
if (DistinctIndices(X[i+l], X[i+m], hashLen, lenIndices)) {
|
||||
auto soln = res.GetIndices(hashLen, 2*lenIndices, CollisionBitLength);
|
||||
@@ -475,20 +532,21 @@ bool Equihash<N,K>::BasicSolve(const eh_HashState& base_state,
|
||||
template<size_t WIDTH>
|
||||
void CollideBranches(std::vector<FullStepRow<WIDTH>>& X, const size_t hlen, const size_t lenIndices, const unsigned int clen, const unsigned int ilen, const eh_trunc lt, const eh_trunc rt)
|
||||
{
|
||||
int i = 0;
|
||||
int posFree = 0;
|
||||
size_t i = 0;
|
||||
size_t posFree = 0;
|
||||
assert(X.size() > 0);
|
||||
std::vector<FullStepRow<WIDTH>> Xc;
|
||||
while (i < X.size() - 1) {
|
||||
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
||||
int j = 1;
|
||||
size_t j = 1;
|
||||
while (i+j < X.size() &&
|
||||
HasCollision(X[i], X[i+j], clen)) {
|
||||
j++;
|
||||
}
|
||||
|
||||
// 2c) Calculate tuples (X_i ^ X_j, (i, j))
|
||||
for (int l = 0; l < j - 1; l++) {
|
||||
for (int m = l + 1; m < j; m++) {
|
||||
for (size_t l = 0; l < j - 1; l++) {
|
||||
for (size_t m = l + 1; m < j; m++) {
|
||||
if (DistinctIndices(X[i+l], X[i+m], hlen, lenIndices)) {
|
||||
if (IsValidBranch(X[i+l], hlen, ilen, lt) && IsValidBranch(X[i+m], hlen, ilen, rt)) {
|
||||
Xc.emplace_back(X[i+l], X[i+m], hlen, lenIndices, clen);
|
||||
@@ -526,10 +584,10 @@ void CollideBranches(std::vector<FullStepRow<WIDTH>>& X, const size_t hlen, cons
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
eh_index init_size { 1 << (CollisionBitLength + 1) };
|
||||
eh_index init_size { 1U << (CollisionBitLength + 1) };
|
||||
eh_index recreate_size { UntruncateIndex(1, 0, CollisionBitLength + 1) };
|
||||
|
||||
// First run the algorithm with truncated indices
|
||||
@@ -547,16 +605,16 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
Xt.reserve(init_size);
|
||||
unsigned char tmpHash[HashOutput];
|
||||
for (eh_index g = 0; Xt.size() < init_size; g++) {
|
||||
GenerateHash(base_state, g, tmpHash, HashOutput);
|
||||
GenerateHash(base_state, g, tmpHash, HashOutput, N);
|
||||
for (eh_index i = 0; i < IndicesPerHashOutput && Xt.size() < init_size; i++) {
|
||||
Xt.emplace_back(tmpHash+(i*N/8), N/8, HashLength, CollisionBitLength,
|
||||
(g*IndicesPerHashOutput)+i, CollisionBitLength + 1);
|
||||
Xt.emplace_back(tmpHash+(i*GetSizeInBytes(N)), GetSizeInBytes(N), HashLength, CollisionBitLength,
|
||||
static_cast<eh_index>(g*IndicesPerHashOutput)+i, static_cast<unsigned int>(CollisionBitLength + 1));
|
||||
}
|
||||
if (cancelled(ListGeneration)) throw solver_cancelled;
|
||||
}
|
||||
|
||||
// 3) Repeat step 2 until 2n/(k+1) bits remain
|
||||
for (int r = 1; r < K && Xt.size() > 0; r++) {
|
||||
for (unsigned int r = 1; r < K && Xt.size() > 0; r++) {
|
||||
LogPrint("pow", "Round %d:\n", r);
|
||||
// 2a) Sort the list
|
||||
LogPrint("pow", "- Sorting list\n");
|
||||
@@ -564,21 +622,21 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
if (cancelled(ListSorting)) throw solver_cancelled;
|
||||
|
||||
LogPrint("pow", "- Finding collisions\n");
|
||||
int i = 0;
|
||||
int posFree = 0;
|
||||
size_t i = 0;
|
||||
size_t posFree = 0;
|
||||
std::vector<TruncatedStepRow<TruncatedWidth>> Xc;
|
||||
while (i < Xt.size() - 1) {
|
||||
// 2b) Find next set of unordered pairs with collisions on the next n/(k+1) bits
|
||||
int j = 1;
|
||||
size_t j = 1;
|
||||
while (i+j < Xt.size() &&
|
||||
HasCollision(Xt[i], Xt[i+j], CollisionByteLength)) {
|
||||
j++;
|
||||
}
|
||||
|
||||
// 2c) Calculate tuples (X_i ^ X_j, (i, j))
|
||||
bool checking_for_zero = (i == 0 && Xt[0].IsZero(hashLen));
|
||||
for (int l = 0; l < j - 1; l++) {
|
||||
for (int m = l + 1; m < j; m++) {
|
||||
//bool checking_for_zero = (i == 0 && Xt[0].IsZero(hashLen));
|
||||
for (size_t l = 0; l < j - 1; l++) {
|
||||
for (size_t m = l + 1; m < j; m++) {
|
||||
// We truncated, so don't check for distinct indices here
|
||||
TruncatedStepRow<TruncatedWidth> Xi {Xt[i+l], Xt[i+m],
|
||||
hashLen, lenIndices,
|
||||
@@ -628,16 +686,16 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
std::sort(Xt.begin(), Xt.end(), CompareSR(hashLen));
|
||||
if (cancelled(FinalSorting)) throw solver_cancelled;
|
||||
LogPrint("pow", "- Finding collisions\n");
|
||||
int i = 0;
|
||||
size_t i = 0;
|
||||
while (i < Xt.size() - 1) {
|
||||
int j = 1;
|
||||
size_t j = 1;
|
||||
while (i+j < Xt.size() &&
|
||||
HasCollision(Xt[i], Xt[i+j], hashLen)) {
|
||||
j++;
|
||||
}
|
||||
|
||||
for (int l = 0; l < j - 1; l++) {
|
||||
for (int m = l + 1; m < j; m++) {
|
||||
for (size_t l = 0; l < j - 1; l++) {
|
||||
for (size_t m = l + 1; m < j; m++) {
|
||||
TruncatedStepRow<FinalTruncatedWidth> res(Xt[i+l], Xt[i+m],
|
||||
hashLen, lenIndices, 0);
|
||||
auto soln = res.GetTruncatedIndices(hashLen, 2*lenIndices);
|
||||
@@ -676,10 +734,10 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
eh_index newIndex { UntruncateIndex(partialSoln.get()[i], j, CollisionBitLength + 1) };
|
||||
if (j == 0 || newIndex % IndicesPerHashOutput == 0) {
|
||||
GenerateHash(base_state, newIndex/IndicesPerHashOutput,
|
||||
tmpHash, HashOutput);
|
||||
tmpHash, HashOutput, N);
|
||||
}
|
||||
icv.emplace_back(tmpHash+((newIndex % IndicesPerHashOutput) * N/8),
|
||||
N/8, HashLength, CollisionBitLength, newIndex);
|
||||
icv.emplace_back(tmpHash+((newIndex % IndicesPerHashOutput) * GetSizeInBytes(N)),
|
||||
GetSizeInBytes(N), HashLength, CollisionBitLength, newIndex);
|
||||
if (cancelled(PartialGeneration)) throw solver_cancelled;
|
||||
}
|
||||
boost::optional<std::vector<FullStepRow<FinalFullWidth>>> ic = icv;
|
||||
@@ -697,7 +755,7 @@ bool Equihash<N,K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
ic->insert(ic->end(), X[r]->begin(), X[r]->end());
|
||||
std::sort(ic->begin(), ic->end(), CompareSR(hashLen));
|
||||
if (cancelled(PartialSorting)) throw solver_cancelled;
|
||||
size_t lti = rti-(1<<r);
|
||||
size_t lti = rti-(static_cast<size_t>(1)<<r);
|
||||
CollideBranches(*ic, hashLen, lenIndices,
|
||||
CollisionByteLength,
|
||||
CollisionBitLength + 1,
|
||||
@@ -760,16 +818,16 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<
|
||||
X.reserve(1 << K);
|
||||
unsigned char tmpHash[HashOutput];
|
||||
for (eh_index i : GetIndicesFromMinimal(soln, CollisionBitLength)) {
|
||||
GenerateHash(base_state, i/IndicesPerHashOutput, tmpHash, HashOutput);
|
||||
X.emplace_back(tmpHash+((i % IndicesPerHashOutput) * N/8),
|
||||
N/8, HashLength, CollisionBitLength, i);
|
||||
GenerateHash(base_state, i/IndicesPerHashOutput, tmpHash, HashOutput, N);
|
||||
X.emplace_back(tmpHash+((i % IndicesPerHashOutput) * GetSizeInBytes(N)),
|
||||
GetSizeInBytes(N), HashLength, CollisionBitLength, i);
|
||||
}
|
||||
|
||||
size_t hashLen = HashLength;
|
||||
size_t lenIndices = sizeof(eh_index);
|
||||
while (X.size() > 1) {
|
||||
std::vector<FullStepRow<FinalFullWidth>> Xc;
|
||||
for (int i = 0; i < X.size(); i += 2) {
|
||||
for (size_t i = 0; i < X.size(); i += 2) {
|
||||
if (!HasCollision(X[i], X[i+1], CollisionByteLength)) {
|
||||
LogPrint("pow", "Invalid solution: invalid collision length between StepRows\n");
|
||||
LogPrint("pow", "X[i] = %s\n", X[i].GetHex(hashLen));
|
||||
@@ -795,50 +853,74 @@ bool Equihash<N,K>::IsValidSolution(const eh_HashState& base_state, std::vector<
|
||||
return X[0].IsZero(hashLen);
|
||||
}
|
||||
|
||||
// Explicit instantiations for Equihash<96,3>
|
||||
template int Equihash<96,3>::InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
template bool Equihash<96,3>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<96,3>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
template bool Equihash<96,3>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<200,9>
|
||||
template int Equihash<200,9>::InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
template bool Equihash<200,9>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<200,9>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
template bool Equihash<200,9>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<96,5>
|
||||
template int Equihash<96,5>::InitialiseState(eh_HashState& base_state);
|
||||
|
||||
// Explicit instantiations for Equihash<96,3>
|
||||
template int Equihash<150,5>::InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
template bool Equihash<96,5>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
template bool Equihash<150,5>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<96,5>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
template bool Equihash<150,5>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
template bool Equihash<96,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
template bool Equihash<150,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<48,5>
|
||||
template int Equihash<144,5>::InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
template bool Equihash<144,5>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<144,5>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
template bool Equihash<144,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<96,5>
|
||||
template int Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
template bool Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
template bool Equihash<ASSETCHAINS_N,ASSETCHAINS_K>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<96,5>
|
||||
template int Equihash<48,5>::InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
template bool Equihash<48,5>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<48,5>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
template bool Equihash<48,5>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
// Explicit instantiations for Equihash<48,5>
|
||||
template int Equihash<210,9>::InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
template bool Equihash<210,9>::BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
template bool Equihash<210,9>::OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
template bool Equihash<210,9>::IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
#include "sodium.h"
|
||||
#include "komodo_nk.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
@@ -24,6 +25,9 @@ typedef crypto_generichash_blake2b_state eh_HashState;
|
||||
typedef uint32_t eh_index;
|
||||
typedef uint8_t eh_trunc;
|
||||
|
||||
#define BLAKE2B_OUTBYTES 64
|
||||
extern uint64_t ASSETCHAINS_NK[2];
|
||||
|
||||
void ExpandArray(const unsigned char* in, size_t in_len,
|
||||
unsigned char* out, size_t out_len,
|
||||
size_t bit_len, size_t byte_pad=0);
|
||||
@@ -61,7 +65,7 @@ public:
|
||||
std::string GetHex(size_t len) { return HexStr(hash, hash+len); }
|
||||
|
||||
template<size_t W>
|
||||
friend bool HasCollision(StepRow<W>& a, StepRow<W>& b, int l);
|
||||
friend bool HasCollision(StepRow<W>& a, StepRow<W>& b, size_t l);
|
||||
};
|
||||
|
||||
class CompareSR
|
||||
@@ -77,7 +81,7 @@ public:
|
||||
};
|
||||
|
||||
template<size_t WIDTH>
|
||||
bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, int l);
|
||||
bool HasCollision(StepRow<WIDTH>& a, StepRow<WIDTH>& b, size_t l);
|
||||
|
||||
template<size_t WIDTH>
|
||||
class FullStepRow : public StepRow<WIDTH>
|
||||
@@ -94,7 +98,7 @@ public:
|
||||
|
||||
FullStepRow(const FullStepRow<WIDTH>& a) : StepRow<WIDTH> {a} { }
|
||||
template<size_t W>
|
||||
FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, int trim);
|
||||
FullStepRow(const FullStepRow<W>& a, const FullStepRow<W>& b, size_t len, size_t lenIndices, size_t trim);
|
||||
FullStepRow& operator=(const FullStepRow<WIDTH>& a);
|
||||
|
||||
inline bool IndicesBefore(const FullStepRow<WIDTH>& a, size_t len, size_t lenIndices) const { return memcmp(hash+len, a.hash+len, lenIndices) < 0; }
|
||||
@@ -159,17 +163,22 @@ inline constexpr size_t equihash_solution_size(unsigned int N, unsigned int K) {
|
||||
return (1 << K)*(N/(K+1)+1)/8;
|
||||
}
|
||||
|
||||
constexpr uint8_t GetSizeInBytes(size_t N)
|
||||
{
|
||||
return static_cast<uint8_t>((N + 7) / 8);
|
||||
}
|
||||
|
||||
template<unsigned int N, unsigned int K>
|
||||
class Equihash
|
||||
{
|
||||
private:
|
||||
BOOST_STATIC_ASSERT(K < N);
|
||||
BOOST_STATIC_ASSERT(N % 8 == 0);
|
||||
//BOOST_STATIC_ASSERT(N % 8 == 0);
|
||||
BOOST_STATIC_ASSERT((N/(K+1)) + 1 < 8*sizeof(eh_index));
|
||||
|
||||
public:
|
||||
enum : size_t { IndicesPerHashOutput=512/N };
|
||||
enum : size_t { HashOutput=IndicesPerHashOutput*N/8 };
|
||||
enum : size_t { HashOutput = IndicesPerHashOutput * GetSizeInBytes(N) };
|
||||
enum : size_t { CollisionBitLength=N/(K+1) };
|
||||
enum : size_t { CollisionByteLength=(CollisionBitLength+7)/8 };
|
||||
enum : size_t { HashLength=(K+1)*CollisionByteLength };
|
||||
@@ -184,79 +193,100 @@ public:
|
||||
int InitialiseState(eh_HashState& base_state);
|
||||
#ifdef ENABLE_MINING
|
||||
bool BasicSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
bool OptimisedSolve(const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled);
|
||||
#endif
|
||||
bool IsValidSolution(const eh_HashState& base_state, std::vector<unsigned char> soln);
|
||||
};
|
||||
|
||||
#include "equihash.tcc"
|
||||
/*
|
||||
* Equihash 200,9 (KMD/Zcash)
|
||||
* Equihash 150,5 (beam)
|
||||
* Equihash 144,5 (SnowGem)
|
||||
* Equihash 96,5 (Minex)
|
||||
* Equihash 48,5 (regtest)
|
||||
* Equihash 210,9 (Aion) */
|
||||
|
||||
static Equihash<96,3> Eh96_3;
|
||||
static Equihash<200,9> Eh200_9;
|
||||
static Equihash<96,5> Eh96_5;
|
||||
static Equihash<150,5> Eh150_5;
|
||||
static Equihash<144,5> Eh144_5;
|
||||
static Equihash<ASSETCHAINS_N,ASSETCHAINS_K> Eh96_5;
|
||||
static Equihash<48,5> Eh48_5;
|
||||
static Equihash<210,9> Eh210_9;
|
||||
|
||||
#define EhInitialiseState(n, k, base_state) \
|
||||
if (n == 96 && k == 3) { \
|
||||
Eh96_3.InitialiseState(base_state); \
|
||||
} else if (n == 200 && k == 9) { \
|
||||
Eh200_9.InitialiseState(base_state); \
|
||||
} else if (n == 96 && k == 5) { \
|
||||
if (n == 200 && k == 9) { \
|
||||
Eh200_9.InitialiseState(base_state); \
|
||||
} else if (n == 150 && k == 5) { \
|
||||
Eh150_5.InitialiseState(base_state); \
|
||||
} else if (n == 144 && k == 5) { \
|
||||
Eh144_5.InitialiseState(base_state); \
|
||||
} else if (n == ASSETCHAINS_N && k == ASSETCHAINS_K) { \
|
||||
Eh96_5.InitialiseState(base_state); \
|
||||
} else if (n == 48 && k == 5) { \
|
||||
Eh48_5.InitialiseState(base_state); \
|
||||
} else if (n == 210 && k == 9) { \
|
||||
Eh210_9.InitialiseState(base_state); \
|
||||
} else { \
|
||||
throw std::invalid_argument("Unsupported Equihash parameters"); \
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MINING
|
||||
inline bool EhBasicSolve(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
if (n == 96 && k == 3) {
|
||||
return Eh96_3.BasicSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 200 && k == 9) {
|
||||
if (n == 200 && k == 9) {
|
||||
return Eh200_9.BasicSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 96 && k == 5) {
|
||||
} else if (n == 150 && k == 5) {
|
||||
return Eh150_5.BasicSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 144 && k == 5) {
|
||||
return Eh144_5.BasicSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == ASSETCHAINS_N && k == ASSETCHAINS_K) {
|
||||
return Eh96_5.BasicSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 48 && k == 5) {
|
||||
} else if (n == 48 && k == 5) {
|
||||
return Eh48_5.BasicSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 210 && k == 9) {
|
||||
return Eh210_9.BasicSolve(base_state, validBlock, cancelled);
|
||||
} else {
|
||||
throw std::invalid_argument("Unsupported Equihash parameters");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EhBasicSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock)
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock)
|
||||
{
|
||||
return EhBasicSolve(n, k, base_state, validBlock,
|
||||
[](EhSolverCancelCheck pos) { return false; });
|
||||
}
|
||||
|
||||
inline bool EhOptimisedSolve(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock,
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock,
|
||||
const std::function<bool(EhSolverCancelCheck)> cancelled)
|
||||
{
|
||||
if (n == 96 && k == 3) {
|
||||
return Eh96_3.OptimisedSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 200 && k == 9) {
|
||||
if (n == 200 && k == 9) {
|
||||
return Eh200_9.OptimisedSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 96 && k == 5) {
|
||||
} else if (n == 150 && k == 5) {
|
||||
return Eh150_5.OptimisedSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 144 && k == 5) {
|
||||
return Eh144_5.OptimisedSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == ASSETCHAINS_N && k == ASSETCHAINS_K) {
|
||||
return Eh96_5.OptimisedSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 48 && k == 5) {
|
||||
} else if (n == 48 && k == 5) {
|
||||
return Eh48_5.OptimisedSolve(base_state, validBlock, cancelled);
|
||||
} else if (n == 210 && k == 9) {
|
||||
return Eh210_9.OptimisedSolve(base_state, validBlock, cancelled);
|
||||
} else {
|
||||
throw std::invalid_argument("Unsupported Equihash parameters");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool EhOptimisedSolveUncancellable(unsigned int n, unsigned int k, const eh_HashState& base_state,
|
||||
const std::function<bool(std::vector<unsigned char>)> validBlock)
|
||||
const std::function<bool(const std::vector<unsigned char>&)> validBlock)
|
||||
{
|
||||
return EhOptimisedSolve(n, k, base_state, validBlock,
|
||||
[](EhSolverCancelCheck pos) { return false; });
|
||||
@@ -264,14 +294,18 @@ inline bool EhOptimisedSolveUncancellable(unsigned int n, unsigned int k, const
|
||||
#endif // ENABLE_MINING
|
||||
|
||||
#define EhIsValidSolution(n, k, base_state, soln, ret) \
|
||||
if (n == 96 && k == 3) { \
|
||||
ret = Eh96_3.IsValidSolution(base_state, soln); \
|
||||
} else if (n == 200 && k == 9) { \
|
||||
ret = Eh200_9.IsValidSolution(base_state, soln); \
|
||||
} else if (n == 96 && k == 5) { \
|
||||
if (n == 200 && k == 9) { \
|
||||
ret = Eh200_9.IsValidSolution(base_state, soln); \
|
||||
} else if (n == 150 && k == 5) { \
|
||||
ret = Eh150_5.IsValidSolution(base_state, soln); \
|
||||
} else if (n == 144 && k == 5) { \
|
||||
ret = Eh144_5.IsValidSolution(base_state, soln); \
|
||||
} else if (n == ASSETCHAINS_N && k == ASSETCHAINS_K) { \
|
||||
ret = Eh96_5.IsValidSolution(base_state, soln); \
|
||||
} else if (n == 48 && k == 5) { \
|
||||
ret = Eh48_5.IsValidSolution(base_state, soln); \
|
||||
} else if (n == 210 && k == 9) { \
|
||||
ret = Eh210_9.IsValidSolution(base_state, soln); \
|
||||
} else { \
|
||||
throw std::invalid_argument("Unsupported Equihash parameters"); \
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ void lockSign() {
|
||||
}
|
||||
if (!secp256k1_context_randomize(ec_ctx_sign, ent)) {
|
||||
fprintf(stderr, "Could not randomize secp256k1 context\n");
|
||||
exit(1);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
src/fiat/vote2019
Executable file
2
src/fiat/vote2019
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
./komodo-cli -ac_name=VOTE2019 $1 $2 $3 $4 $5 $6
|
||||
@@ -5,7 +5,7 @@
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd $DIR
|
||||
|
||||
NAME=HUSHT3
|
||||
NAME=HUSH3T
|
||||
|
||||
CLI=${KOMODOCLI:-./komodo-cli}
|
||||
$CLI -ac_name=$NAME "$@"
|
||||
|
||||
@@ -30,7 +30,6 @@ HEIR=234
|
||||
CHANNEL=235
|
||||
ORACLE=236
|
||||
GATEWAY=241
|
||||
DILITHIUM=
|
||||
CCENABLE=$FAUCET,$HEIR,$CHANNEL,$ORACLE,$GATEWAY
|
||||
|
||||
#NOTE: This is not compatible with upstream KMD komodod,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Copyright (c) 2019 Hush developers
|
||||
|
||||
# set working directory to the location of this script
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
DIR="$( cd "$( dirname "$( readlink -f "${BASH_SOURCE[0]}" )" )" && pwd )"
|
||||
cd $DIR
|
||||
|
||||
# TESTING VALUES, DO NOT USE EXCEPT FOR DEVELOPMENT
|
||||
@@ -12,15 +12,16 @@ SCRIPT=76a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac
|
||||
|
||||
# Chain parameters
|
||||
ERAS=3
|
||||
BLOCKTIME=10
|
||||
SUPPLY=6250000
|
||||
BLOCKTIME=150
|
||||
# 6250000 - (sprout pool at block 500,000)
|
||||
SUPPLY=6178674
|
||||
FOUNDERS=1
|
||||
REWARD=0,1125000000,562500000
|
||||
HALVING=29,34,84
|
||||
END=28,34,501
|
||||
PERC=11111111
|
||||
HALVING=129,340000,840000
|
||||
# NOTE: keep in sync with komodo_bitcoind.h
|
||||
END=128,340000,5422111
|
||||
CLIENTNAME=GoldenSandtrout
|
||||
PERC=11111111
|
||||
SEEDNODE=188.165.212.101
|
||||
CCLIB=hush3
|
||||
|
||||
@@ -32,6 +33,9 @@ ORACLE=236
|
||||
GATEWAY=241
|
||||
CCENABLE=$FAUCET,$HEIR,$CHANNEL,$ORACLE,$GATEWAY
|
||||
|
||||
#NOTE: This is not compatible with upstream KMD komodod,
|
||||
# but you can reuse one hush3 komodod binary in various
|
||||
# directories/repos on one server, to save disk space
|
||||
KMD=${KOMODOD:-./komodod}
|
||||
$KMD -ac_name=$NAME -ac_sapling=1 \
|
||||
-ac_reward=$REWARD \
|
||||
@@ -39,7 +43,6 @@ $KMD -ac_name=$NAME -ac_sapling=1 \
|
||||
-ac_end=$END \
|
||||
-ac_eras=$ERAS \
|
||||
-ac_blocktime=$BLOCKTIME \
|
||||
-ac_perc=$PERC \
|
||||
-ac_cc=2 -ac_ccenable=$CCENABLE \
|
||||
-ac_founders=$FOUNDERS -ac_supply=$SUPPLY \
|
||||
-ac_perc=$PERC \
|
||||
|
||||
@@ -24,28 +24,63 @@
|
||||
#include "script/sign.h"
|
||||
#include "wallet/wallet.h"
|
||||
|
||||
#include "cc/CCinclude.h"
|
||||
|
||||
int32_t komodo_nextheight();
|
||||
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts, uint32_t nExpiryHeightOverride)
|
||||
// makes import tx for either coins or tokens
|
||||
CTransaction MakeImportCoinTransaction(const ImportProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts, uint32_t nExpiryHeightOverride)
|
||||
{
|
||||
std::vector<uint8_t> payload = E_MARSHAL(ss << EVAL_IMPORTCOIN);
|
||||
//std::vector<uint8_t> payload = E_MARSHAL(ss << EVAL_IMPORTCOIN);
|
||||
CScript scriptSig;
|
||||
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
if (mtx.fOverwintered)
|
||||
mtx.nExpiryHeight = 0;
|
||||
mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload));
|
||||
mtx.vout = payouts;
|
||||
auto importData = E_MARSHAL(ss << proof; ss << burnTx);
|
||||
mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << importData));
|
||||
if (nExpiryHeightOverride != 0)
|
||||
mtx.nExpiryHeight = nExpiryHeightOverride; //this is for construction of the tx used for validating importtx
|
||||
if (mtx.vout.size() == 0)
|
||||
return CTransaction(mtx);
|
||||
|
||||
// add special import tx vin:
|
||||
scriptSig << E_MARSHAL(ss << EVAL_IMPORTCOIN); // simple payload for coins
|
||||
mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), scriptSig));
|
||||
|
||||
if (nExpiryHeightOverride != 0)
|
||||
mtx.nExpiryHeight = nExpiryHeightOverride; //this is for validation code, to make a tx used for validating the import tx
|
||||
|
||||
auto importData = E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << proof; ss << burnTx); // added evalcode to differentiate importdata from token opret
|
||||
// if it is tokens:
|
||||
vscript_t vopret;
|
||||
GetOpReturnData(mtx.vout.back().scriptPubKey, vopret);
|
||||
|
||||
if (!vopret.empty()) {
|
||||
std::vector<uint8_t> vorigpubkey;
|
||||
uint8_t funcId;
|
||||
std::vector <std::pair<uint8_t, vscript_t>> oprets;
|
||||
std::string name, desc;
|
||||
|
||||
if (DecodeTokenCreateOpRet(mtx.vout.back().scriptPubKey, vorigpubkey, name, desc, oprets) == 'c') { // parse token 'c' opret
|
||||
mtx.vout.pop_back(); //remove old token opret
|
||||
oprets.push_back(std::make_pair(OPRETID_IMPORTDATA, importData));
|
||||
mtx.vout.push_back(CTxOut(0, EncodeTokenCreateOpRet('c', vorigpubkey, name, desc, oprets))); // make new token 'c' opret with importData
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeImportCoinTransaction() incorrect token import opret" << std::endl);
|
||||
}
|
||||
}
|
||||
else { //no opret in coin payouts
|
||||
mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << importData)); // import tx's opret now is in the vout's tail
|
||||
}
|
||||
|
||||
return CTransaction(mtx);
|
||||
}
|
||||
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts,std::vector<uint8_t> rawproof)
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string targetSymbol, const std::vector<CTxOut> payouts, const std::vector<uint8_t> rawproof)
|
||||
{
|
||||
std::vector<uint8_t> opret;
|
||||
opret = E_MARSHAL(ss << VARINT(targetCCid);
|
||||
opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; // should mark burn opret to differentiate it from token opret
|
||||
ss << VARINT(targetCCid);
|
||||
ss << targetSymbol;
|
||||
ss << SerializeHash(payouts);
|
||||
ss << rawproof);
|
||||
@@ -53,20 +88,23 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb
|
||||
}
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts,std::vector<uint8_t> rawproof,
|
||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub)
|
||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256> txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount)
|
||||
{
|
||||
std::vector<uint8_t> opret;
|
||||
opret = E_MARSHAL(ss << VARINT(targetCCid);
|
||||
opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN;
|
||||
ss << VARINT(targetCCid);
|
||||
ss << targetSymbol;
|
||||
ss << SerializeHash(payouts);
|
||||
ss << rawproof;
|
||||
ss << bindtxid;
|
||||
ss << publishers;
|
||||
ss << txids;
|
||||
ss << burntxid;
|
||||
ss << height;
|
||||
ss << burnvout;
|
||||
ss << rawburntx;
|
||||
ss << destpub);
|
||||
ss << destpub;
|
||||
ss << amount);
|
||||
|
||||
return CTxOut(value, CScript() << OP_RETURN << opret);
|
||||
}
|
||||
@@ -75,7 +113,8 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb
|
||||
std::string receipt)
|
||||
{
|
||||
std::vector<uint8_t> opret;
|
||||
opret = E_MARSHAL(ss << VARINT(targetCCid);
|
||||
opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN;
|
||||
ss << VARINT(targetCCid);
|
||||
ss << targetSymbol;
|
||||
ss << SerializeHash(payouts);
|
||||
ss << rawproof;
|
||||
@@ -85,39 +124,114 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb
|
||||
}
|
||||
|
||||
|
||||
bool UnmarshalImportTx(const CTransaction importTx, TxProof &proof, CTransaction &burnTx,
|
||||
std::vector<CTxOut> &payouts)
|
||||
bool UnmarshalImportTx(const CTransaction importTx, ImportProof &proof, CTransaction &burnTx, std::vector<CTxOut> &payouts)
|
||||
{
|
||||
std::vector<uint8_t> vData;
|
||||
GetOpReturnData(importTx.vout[importTx.vout.size()-1].scriptPubKey, vData);
|
||||
if (importTx.vout.size() < 1) return false;
|
||||
payouts = std::vector<CTxOut>(importTx.vout.begin(), importTx.vout.end()-1);
|
||||
return importTx.vin.size() == 1 &&
|
||||
importTx.vin[0].scriptSig == (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN)) &&
|
||||
E_UNMARSHAL(vData, ss >> proof; ss >> burnTx);
|
||||
if (importTx.vout.size() < 1)
|
||||
return false;
|
||||
|
||||
if (importTx.vin.size() != 1 || importTx.vin[0].scriptSig != (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN))) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() incorrect import tx vin" << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> vImportData;
|
||||
GetOpReturnData(importTx.vout.back().scriptPubKey, vImportData);
|
||||
if (vImportData.empty()) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() no opret" << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vImportData.begin()[0] == EVAL_TOKENS) { // if it is tokens
|
||||
// get import data after token opret:
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
std::vector<uint8_t> vorigpubkey;
|
||||
std::string name, desc;
|
||||
|
||||
if (DecodeTokenCreateOpRet(importTx.vout.back().scriptPubKey, vorigpubkey, name, desc, oprets) == 0) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() could not decode token opret" << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
GetOpretBlob(oprets, OPRETID_IMPORTDATA, vImportData); // fetch import data after token opret
|
||||
for (std::vector<std::pair<uint8_t, vscript_t>>::const_iterator i = oprets.begin(); i != oprets.end(); i++)
|
||||
if ((*i).first == OPRETID_IMPORTDATA) {
|
||||
oprets.erase(i); // remove import data from token opret to restore original payouts:
|
||||
break;
|
||||
}
|
||||
|
||||
payouts = std::vector<CTxOut>(importTx.vout.begin(), importTx.vout.end()-1); //exclude opret with import data
|
||||
payouts.push_back(CTxOut(0, EncodeTokenCreateOpRet('c', vorigpubkey, name, desc, oprets))); // make original payouts token opret (without import data)
|
||||
}
|
||||
else {
|
||||
//payouts = std::vector<CTxOut>(importTx.vout.begin()+1, importTx.vout.end()); // see next
|
||||
payouts = std::vector<CTxOut>(importTx.vout.begin(), importTx.vout.end() - 1); // skip opret; and it is now in the back
|
||||
}
|
||||
|
||||
uint8_t evalCode;
|
||||
bool retcode = E_UNMARSHAL(vImportData, ss >> evalCode; ss >> proof; ss >> burnTx);
|
||||
if (!retcode)
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() could not unmarshal import data" << std::endl);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector<uint8_t>&rawproof)
|
||||
{
|
||||
std::vector<uint8_t> burnOpret; uint32_t ccid = 0; bool isEof=true;
|
||||
std::vector<uint8_t> vburnOpret; uint32_t ccid = 0;
|
||||
uint8_t evalCode;
|
||||
|
||||
if (burnTx.vout.size() == 0) return false;
|
||||
GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret);
|
||||
return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid);
|
||||
ss >> targetSymbol;
|
||||
ss >> payoutsHash;
|
||||
ss >> rawproof; isEof=ss.eof();) || !isEof;
|
||||
if (burnTx.vout.size() == 0)
|
||||
return false;
|
||||
|
||||
GetOpReturnData(burnTx.vout.back().scriptPubKey, vburnOpret);
|
||||
if (vburnOpret.empty()) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() cannot unmarshal burn tx: empty burn opret" << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vburnOpret.begin()[0] == EVAL_TOKENS) { //if it is tokens
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
uint256 tokenid;
|
||||
uint8_t evalCodeInOpret;
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
|
||||
if (DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) != 't')
|
||||
return false;
|
||||
|
||||
//skip token opret:
|
||||
GetOpretBlob(oprets, OPRETID_BURNDATA, vburnOpret); // fetch burnOpret after token opret
|
||||
if (vburnOpret.empty()) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() cannot unmarshal token burn tx: empty burn opret for tokenid=" << tokenid.GetHex() << std::endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (vburnOpret.begin()[0] == EVAL_IMPORTCOIN) {
|
||||
uint8_t evalCode;
|
||||
bool isEof = true;
|
||||
return E_UNMARSHAL(vburnOpret, ss >> evalCode;
|
||||
ss >> VARINT(*targetCCid);
|
||||
ss >> targetSymbol;
|
||||
ss >> payoutsHash;
|
||||
ss >> rawproof; isEof = ss.eof();) || !isEof; // if isEof == false it means we have successfully read the vars upto 'rawproof'
|
||||
// and it might be additional data further that we do not need here so we allow !isEof
|
||||
}
|
||||
else {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() invalid eval code in opret" << std::endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt)
|
||||
{
|
||||
std::vector<uint8_t> burnOpret,rawproof; bool isEof=true;
|
||||
std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash;
|
||||
uint8_t evalCode;
|
||||
|
||||
if (burnTx.vout.size() == 0) return false;
|
||||
GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret);
|
||||
return (E_UNMARSHAL(burnOpret, ss >> VARINT(targetCCid);
|
||||
return (E_UNMARSHAL(burnOpret, ss >> evalCode;
|
||||
ss >> VARINT(targetCCid);
|
||||
ss >> targetSymbol;
|
||||
ss >> payoutsHash;
|
||||
ss >> rawproof;
|
||||
@@ -125,24 +239,28 @@ bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::strin
|
||||
ss >> receipt));
|
||||
}
|
||||
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector<CPubKey> &publishers,std::vector<uint256> &txids,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub)
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector<CPubKey> &publishers,std::vector<uint256> &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount)
|
||||
{
|
||||
std::vector<uint8_t> burnOpret,rawproof; bool isEof=true;
|
||||
uint32_t targetCCid; uint256 payoutsHash; std::string targetSymbol;
|
||||
uint8_t evalCode;
|
||||
|
||||
if (burnTx.vout.size() == 0) return false;
|
||||
GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret);
|
||||
return (E_UNMARSHAL(burnOpret, ss >> VARINT(targetCCid);
|
||||
return (E_UNMARSHAL(burnOpret, ss >> evalCode;
|
||||
ss >> VARINT(targetCCid);
|
||||
ss >> targetSymbol;
|
||||
ss >> payoutsHash;
|
||||
ss >> rawproof;
|
||||
ss >> bindtxid;
|
||||
ss >> publishers;
|
||||
ss >> txids;
|
||||
ss >> burntxid;
|
||||
ss >> height;
|
||||
ss >> burnvout;
|
||||
ss >> rawburntx;
|
||||
ss >> destpub));
|
||||
ss >> destpub;
|
||||
ss >> amount));
|
||||
}
|
||||
|
||||
|
||||
@@ -151,16 +269,55 @@ bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector<CPu
|
||||
*/
|
||||
CAmount GetCoinImportValue(const CTransaction &tx)
|
||||
{
|
||||
TxProof proof;
|
||||
ImportProof proof;
|
||||
CTransaction burnTx;
|
||||
std::vector<CTxOut> payouts;
|
||||
if (UnmarshalImportTx(tx, proof, burnTx, payouts)) {
|
||||
return burnTx.vout.size() ? burnTx.vout.back().nValue : 0;
|
||||
|
||||
bool isNewImportTx = false;
|
||||
if ((isNewImportTx = UnmarshalImportTx(tx, proof, burnTx, payouts))) {
|
||||
if (burnTx.vout.size() > 0) {
|
||||
vscript_t vburnOpret;
|
||||
|
||||
GetOpReturnData(burnTx.vout.back().scriptPubKey, vburnOpret);
|
||||
if (vburnOpret.empty()) {
|
||||
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetCoinImportValue() empty burn opret" << std::endl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isNewImportTx && vburnOpret.begin()[0] == EVAL_TOKENS) { //if it is tokens
|
||||
|
||||
uint8_t evalCodeInOpret;
|
||||
uint256 tokenid;
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if (DecodeTokenOpRet(tx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) == 0)
|
||||
return 0;
|
||||
|
||||
uint8_t nonfungibleEvalCode = EVAL_TOKENS; // init as if no non-fungibles
|
||||
vscript_t vnonfungibleOpret;
|
||||
GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vnonfungibleOpret);
|
||||
if (!vnonfungibleOpret.empty())
|
||||
nonfungibleEvalCode = vnonfungibleOpret.begin()[0];
|
||||
|
||||
// calc outputs for burn tx
|
||||
int64_t ccBurnOutputs = 0;
|
||||
for (auto v : burnTx.vout)
|
||||
if (v.scriptPubKey.IsPayToCryptoCondition() &&
|
||||
CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(nonfungibleEvalCode, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey
|
||||
ccBurnOutputs += v.nValue;
|
||||
|
||||
return ccBurnOutputs + burnTx.vout.back().nValue; // total token burned value
|
||||
}
|
||||
else
|
||||
return burnTx.vout.back().nValue; // coin burned value
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* CoinImport is different enough from normal script execution that it's not worth
|
||||
* making all the mods neccesary in the interpreter to do the dispatch correctly.
|
||||
|
||||
@@ -22,22 +22,90 @@
|
||||
#include "script/interpreter.h"
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
enum ProofKind : uint8_t {
|
||||
PROOF_NONE = 0x00,
|
||||
PROOF_MERKLEBRANCH = 0x11,
|
||||
PROOF_NOTARYTXIDS = 0x12,
|
||||
PROOF_MERKLEBLOCK = 0x13
|
||||
};
|
||||
|
||||
class ImportProof {
|
||||
|
||||
private:
|
||||
uint8_t proofKind;
|
||||
TxProof proofBranch;
|
||||
std::vector<uint256> notaryTxids;
|
||||
std::vector<uint8_t> proofBlock;
|
||||
|
||||
public:
|
||||
ImportProof() { proofKind = PROOF_NONE; }
|
||||
ImportProof(const TxProof &_proofBranch) {
|
||||
proofKind = PROOF_MERKLEBRANCH; proofBranch = _proofBranch;
|
||||
}
|
||||
ImportProof(const std::vector<uint256> &_notaryTxids) {
|
||||
proofKind = PROOF_NOTARYTXIDS; notaryTxids = _notaryTxids;
|
||||
}
|
||||
ImportProof(const std::vector<uint8_t> &_proofBlock) {
|
||||
proofKind = PROOF_MERKLEBLOCK; proofBlock = _proofBlock;
|
||||
}
|
||||
|
||||
ADD_SERIALIZE_METHODS
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action) {
|
||||
READWRITE(proofKind);
|
||||
if (proofKind == PROOF_MERKLEBRANCH)
|
||||
READWRITE(proofBranch);
|
||||
else if (proofKind == PROOF_NOTARYTXIDS)
|
||||
READWRITE(notaryTxids);
|
||||
else if (proofKind == PROOF_MERKLEBLOCK)
|
||||
READWRITE(proofBlock);
|
||||
else
|
||||
proofKind = PROOF_NONE; // if we have read some trash
|
||||
}
|
||||
|
||||
bool IsMerkleBranch(TxProof &_proofBranch) const {
|
||||
if (proofKind == PROOF_MERKLEBRANCH) {
|
||||
_proofBranch = proofBranch;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
bool IsNotaryTxids(std::vector<uint256> &_notaryTxids) const {
|
||||
if (proofKind == PROOF_NOTARYTXIDS) {
|
||||
_notaryTxids = notaryTxids;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
bool IsMerkleBlock(std::vector<uint8_t> &_proofBlock) const {
|
||||
if (proofKind == PROOF_MERKLEBLOCK) {
|
||||
_proofBlock = proofBlock;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
CAmount GetCoinImportValue(const CTransaction &tx);
|
||||
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof,
|
||||
const CTransaction burnTx, const std::vector<CTxOut> payouts, uint32_t nExpiryHeightOverride = 0);
|
||||
CTransaction MakeImportCoinTransaction(const ImportProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts, uint32_t nExpiryHeightOverride = 0);
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts,std::vector<uint8_t> rawproof);
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string targetSymbol, const std::vector<CTxOut> payouts, const std::vector<uint8_t> rawproof);
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts,std::vector<uint8_t> rawproof,
|
||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256>txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub);
|
||||
uint256 bindtxid,std::vector<CPubKey> publishers,std::vector<uint256>txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount);
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts,std::vector<uint8_t> rawproof,std::string srcaddr,
|
||||
std::string receipt);
|
||||
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector<uint8_t> &rawproof);
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt);
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector<CPubKey> &publishers,std::vector<uint256> &txids,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub);
|
||||
bool UnmarshalImportTx(const CTransaction importTx, TxProof &proof, CTransaction &burnTx,std::vector<CTxOut> &payouts);
|
||||
bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector<CPubKey> &publishers,std::vector<uint256> &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount);
|
||||
bool UnmarshalImportTx(const CTransaction importTx, ImportProof &proof, CTransaction &burnTx,std::vector<CTxOut> &payouts);
|
||||
|
||||
bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state);
|
||||
|
||||
@@ -45,4 +113,9 @@ void AddImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs, i
|
||||
void RemoveImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs);
|
||||
int ExistsImportTombstone(const CTransaction &importTx, const CCoinsViewCache &inputs);
|
||||
|
||||
bool CheckVinPubKey(const CTransaction &sourcetx, int32_t i, uint8_t pubkey33[33]);
|
||||
|
||||
CMutableTransaction MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount);
|
||||
int32_t GetSelfimportProof(const CMutableTransaction sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull);
|
||||
|
||||
#endif /* IMPORTCOIN_H */
|
||||
|
||||
@@ -451,6 +451,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat"));
|
||||
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), true));
|
||||
strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
|
||||
strUsage += HelpMessageOpt("-whitelistaddress=<Raddress>", _("Enable the wallet filter for notary nodes and add one Raddress to the whitelist of the wallet filter. If -whitelistaddress= is used, then the wallet filter is automatically activated. Several Raddresses can be defined using several -whitelistaddress= (similar to -addnode). The wallet filter will filter the utxo to only ones coming from my own Raddress (derived from pubkey) and each Raddress defined using -whitelistaddress= this option is mostly for Notary Nodes)."));
|
||||
strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
|
||||
" " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
|
||||
#endif
|
||||
|
||||
@@ -57,7 +57,7 @@ void init_string(struct return_string *s)
|
||||
if ( s->ptr == NULL )
|
||||
{
|
||||
fprintf(stderr,"init_string malloc() failed\n");
|
||||
exit(-1);
|
||||
StartShutdown();
|
||||
}
|
||||
s->ptr[0] = '\0';
|
||||
}
|
||||
@@ -75,7 +75,8 @@ int tx_height( const uint256 &hash ){
|
||||
nHeight = it->second->GetHeight();
|
||||
//fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
} else {
|
||||
fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() );
|
||||
// Unconfirmed xtns
|
||||
//fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() );
|
||||
}
|
||||
return nHeight;
|
||||
}
|
||||
@@ -94,7 +95,7 @@ size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *
|
||||
if ( s->ptr == NULL )
|
||||
{
|
||||
fprintf(stderr, "accumulate realloc() failed\n");
|
||||
exit(-1);
|
||||
StartShutdown();
|
||||
}
|
||||
memcpy(s->ptr+s->len,ptr,size*nmemb);
|
||||
s->ptr[new_len] = '\0';
|
||||
@@ -371,7 +372,7 @@ char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port)
|
||||
{
|
||||
sprintf(url,(char *)"http://127.0.0.1:%u",port);
|
||||
sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params);
|
||||
//printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS);
|
||||
//printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS);
|
||||
retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params);
|
||||
//retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0);
|
||||
}
|
||||
@@ -448,6 +449,18 @@ int32_t komodo_verifynotarizedscript(int32_t height,uint8_t *script,int32_t len,
|
||||
return(-1);
|
||||
}
|
||||
|
||||
void komodo_reconsiderblock(uint256 blockhash)
|
||||
{
|
||||
char params[256],*jsonstr,*hexstr;
|
||||
sprintf(params,"[\"%s\"]",blockhash.ToString().c_str());
|
||||
if ( (jsonstr= komodo_issuemethod(ASSETCHAINS_USERPASS,(char *)"reconsiderblock",params,ASSETCHAINS_RPCPORT)) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"komodo_reconsiderblock.(%s) (%s %u) -> (%s)\n",params,ASSETCHAINS_USERPASS,ASSETCHAINS_RPCPORT,jsonstr);
|
||||
free(jsonstr);
|
||||
}
|
||||
//fprintf(stderr,"komodo_reconsiderblock.(%s) (%s %u) -> NULL\n",params,ASSETCHAINS_USERPASS,ASSETCHAINS_RPCPORT);
|
||||
}
|
||||
|
||||
int32_t komodo_verifynotarization(char *symbol,char *dest,int32_t height,int32_t NOTARIZED_HEIGHT,uint256 NOTARIZED_HASH,uint256 NOTARIZED_DESTTXID)
|
||||
{
|
||||
char params[256],*jsonstr,*hexstr; uint8_t *script,_script[8192]; int32_t n,len,retval = -1; cJSON *json,*txjson,*vouts,*vout,*skey;
|
||||
@@ -1079,6 +1092,17 @@ int32_t komodo_blockheight(uint256 hash)
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint32_t komodo_blocktime(uint256 hash)
|
||||
{
|
||||
BlockMap::const_iterator it; CBlockIndex *pindex = 0;
|
||||
if ( (it = mapBlockIndex.find(hash)) != mapBlockIndex.end() )
|
||||
{
|
||||
if ( (pindex= it->second) != 0 )
|
||||
return(pindex->nTime);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash)
|
||||
{
|
||||
int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex;
|
||||
@@ -1269,8 +1293,9 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height)
|
||||
else commission = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ( pblock != 0 )
|
||||
{
|
||||
txn_count = pblock->vtx.size();
|
||||
for (i=0; i<txn_count; i++)
|
||||
{
|
||||
n = pblock->vtx[i].vout.size();
|
||||
@@ -1882,7 +1907,7 @@ uint64_t komodo_notarypayamount(int32_t nHeight, int64_t notarycount)
|
||||
// Because of reorgs we cannot use the notarized height value.
|
||||
// We need to basically guess here and just pay some static amount.
|
||||
// Has the unwanted effect of varying coin emission, but cannot be helped.
|
||||
fprintf(stderr, "era.%i paying total of %lu\n",curEra, ASSETCHAINS_NOTARY_PAY[curEra]);
|
||||
//fprintf(stderr, "era.%i paying total of %lu\n",curEra, ASSETCHAINS_NOTARY_PAY[curEra]);
|
||||
ret = ASSETCHAINS_NOTARY_PAY[curEra] / notarycount;
|
||||
return(ret);
|
||||
}
|
||||
@@ -1897,13 +1922,8 @@ int32_t komodo_getnotarizedheight(uint32_t timestamp,int32_t height, uint8_t *sc
|
||||
if ( len >= sizeof(uint32_t) && len <= sizeof(scriptbuf) )
|
||||
{
|
||||
memcpy(scriptbuf,script,len);
|
||||
if ( komodo_voutupdate(true,&isratification,0,scriptbuf,len,height,uint256(),1,1,&voutmask,&specialtx,¬arizedheight,0,1,0,timestamp) == -2 )
|
||||
if ( komodo_voutupdate(true,&isratification,0,scriptbuf,len,height,uint256(),1,1,&voutmask,&specialtx,¬arizedheight,0,1,0,timestamp) != -2 )
|
||||
{
|
||||
fprintf(stderr, ">>>>>>VALID NOTARIZATION ht.%i\n",notarizedheight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This should no longer happen. Unless notaries are making actual invalid notarizations.
|
||||
fprintf(stderr, "<<<<<<INVALID NOTARIZATION ht.%i\n",notarizedheight);
|
||||
return(0);
|
||||
}
|
||||
@@ -2056,7 +2076,7 @@ uint64_t komodo_checknotarypay(CBlock *pblock,int32_t height)
|
||||
}
|
||||
if ( matches != 0 && matches == NotarisationNotaries.size() && totalsats == total )
|
||||
{
|
||||
fprintf(stderr, "Validated coinbase matches notarisation in tx position 1.\n" );
|
||||
//fprintf(stderr, "Validated coinbase matches notarisation in tx position 1.\n" );
|
||||
return(totalsats);
|
||||
}
|
||||
return(0);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#ifndef KOMODO_DEFS_H
|
||||
#define KOMODO_DEFS_H
|
||||
#include "komodo_nk.h"
|
||||
|
||||
#define ASSETCHAINS_MINHEIGHT 128
|
||||
#define ASSETCHAINS_MAX_ERAS 3
|
||||
@@ -53,40 +54,62 @@ extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH,ASSETCHAINS_EQUIHASH,KOM
|
||||
extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,KOMODO_ON_DEMAND,KOMODO_PASSPORT_INITDONE,ASSETCHAINS_STAKED;
|
||||
extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_LASTERA,ASSETCHAINS_CBOPRET;
|
||||
extern bool VERUS_MINTBLOCKS;
|
||||
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
|
||||
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[],ASSETCHAINS_NK[2];
|
||||
extern const char *ASSETCHAINS_ALGORITHMS[];
|
||||
extern int32_t VERUS_MIN_STAKEAGE;
|
||||
extern uint32_t ASSETCHAINS_VERUSHASH, ASSETCHAINS_VERUSHASHV1_1, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB;
|
||||
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_MARMARA;
|
||||
extern std::vector<std::string> ASSETCHAINS_PRICES;
|
||||
extern std::vector<std::string> ASSETCHAINS_PRICES,ASSETCHAINS_STOCKS;
|
||||
|
||||
extern char ASSETCHAINS_SYMBOL[65];
|
||||
extern int32_t VERUS_BLOCK_POSUNITS, VERUS_CONSECUTIVE_POS_THRESHOLD, VERUS_NOPOS_THRESHHOLD;
|
||||
|
||||
|
||||
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE,KOMODO_DEALERNODE;
|
||||
extern uint32_t ASSETCHAINS_CC;
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
extern std::string CCerror,ASSETCHAINS_CCLIB;
|
||||
extern uint8_t ASSETCHAINS_CCDISABLES[256];
|
||||
|
||||
extern int32_t USE_EXTERNAL_PUBKEY;
|
||||
extern std::string NOTARY_PUBKEY;
|
||||
extern int32_t KOMODO_EXCHANGEWALLET;
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern int32_t VERUS_MIN_STAKEAGE;
|
||||
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;
|
||||
int tx_height( const uint256 &hash );
|
||||
extern std::vector<std::string> vWhiteListAddress;
|
||||
void komodo_netevent(std::vector<uint8_t> payload);
|
||||
|
||||
#define IGUANA_MAXSCRIPTSIZE 10001
|
||||
#define KOMODO_KVDURATION 1440
|
||||
#define KOMODO_KVBINARY 2
|
||||
#define PRICES_SMOOTHWIDTH 1
|
||||
#define PRICES_MAXDATAPOINTS 8
|
||||
uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume);
|
||||
int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel);
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
|
||||
int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width);
|
||||
int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen);
|
||||
|
||||
uint32_t komodo_blocktime(uint256 hash);
|
||||
int32_t komodo_longestchain();
|
||||
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
|
||||
int8_t komodo_segid(int32_t nocache,int32_t height);
|
||||
int32_t komodo_heightpricebits(uint64_t *seedp,uint32_t *heightbits,int32_t nHeight);
|
||||
char *komodo_pricename(char *name,int32_t ind);
|
||||
int32_t komodo_priceind(char *symbol);
|
||||
void komodo_pricesinit();
|
||||
int32_t komodo_pricesinit();
|
||||
int64_t komodo_priceave(int64_t *tmpbuf,int64_t *correlated,int32_t cskip);
|
||||
int64_t komodo_pricecorrelated(uint64_t seed,int32_t ind,uint32_t *rawprices,int32_t rawskip,uint32_t *nonzprices,int32_t smoothwidth);
|
||||
int32_t komodo_nextheight();
|
||||
uint32_t komodo_heightstamp(int32_t height);
|
||||
int64_t komodo_pricemult(int32_t ind);
|
||||
int32_t komodo_priceget(int64_t *buf64,int32_t ind,int32_t height,int32_t numblocks);
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -653,7 +653,7 @@ int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max)
|
||||
if ( sizeof(banned_txids)/sizeof(*banned_txids) > max )
|
||||
{
|
||||
fprintf(stderr,"komodo_bannedset: buffer too small %ld vs %d\n",sizeof(banned_txids)/sizeof(*banned_txids),max);
|
||||
exit(-1);
|
||||
StartShutdown();
|
||||
}
|
||||
for (i=0; i<sizeof(banned_txids)/sizeof(*banned_txids); i++)
|
||||
array[i] = uint256S(banned_txids[i]);
|
||||
@@ -1555,7 +1555,6 @@ extern std::vector<uint8_t> Mineropret; // opreturn data set by the data gatheri
|
||||
#define KOMODO_LOCALPRICE_CACHESIZE 13
|
||||
#define KOMODO_MAXPRICES 2048
|
||||
#define PRICES_SMOOTHWIDTH 1
|
||||
#define PRICES_MAXDATAPOINTS 8
|
||||
|
||||
#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0)
|
||||
|
||||
@@ -2014,21 +2013,42 @@ cJSON *get_urljson(char *url)
|
||||
return(json);
|
||||
}
|
||||
|
||||
uint32_t get_stockprice(const char *symbol)
|
||||
int32_t get_stockprices(uint32_t now,uint32_t *prices,std::vector<std::string> symbols)
|
||||
{
|
||||
char url[512]; cJSON *json,*obj; uint32_t high,low,price = 0;
|
||||
sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50);
|
||||
if ( (json= get_urljson(url)) != 0 )
|
||||
char url[32768],*symbol,*timestr; cJSON *json,*obj; int32_t i,n=0,retval=-1; uint32_t uprice,timestamp;
|
||||
sprintf(url,"https://api.iextrading.com/1.0/tops/last?symbols=%s",GetArg("-ac_stocks","").c_str());
|
||||
if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"iex")) != 0 ) //
|
||||
{
|
||||
if ( (obj= jobj(json,(char *)"Time Series (15min)")) != 0 )
|
||||
if ( (n= cJSON_GetArraySize(json)) > 0 )
|
||||
{
|
||||
high = jdouble(jitem(obj,0),(char *)"2. high")*10000 + 0.000049;
|
||||
low = jdouble(jitem(obj,0),(char *)"3. low")*10000 + 0.000049;
|
||||
price = (high + low) / 2;
|
||||
retval = n;
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
obj = jitem(json,i);
|
||||
if ( (symbol= jstr(obj,(char *)"symbol")) != 0 )
|
||||
{
|
||||
uprice = jdouble(obj,(char *)"price")*100 + 0.0049;
|
||||
prices[i] = uprice;
|
||||
/*timestamp = j64bits(obj,(char *)"time");
|
||||
if ( timestamp > now+60 || timestamp < now-ASSETCHAINS_BLOCKTIME )
|
||||
{
|
||||
fprintf(stderr,"time error.%d (%u vs %u)\n",timestamp-now,timestamp,now);
|
||||
retval = -1;
|
||||
}*/
|
||||
if ( symbols[i] != symbol )
|
||||
{
|
||||
retval = -1;
|
||||
fprintf(stderr,"MISMATCH.");
|
||||
}
|
||||
fprintf(stderr,"(%s %u) ",symbol,uprice);
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"numstocks.%d\n",n);
|
||||
}
|
||||
//https://api.iextrading.com/1.0/tops/last?symbols=AAPL -> [{"symbol":"AAPL","price":198.63,"size":100,"time":1555092606076}]
|
||||
free_json(json);
|
||||
}
|
||||
return(price);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
uint32_t get_dailyfx(uint32_t *prices)
|
||||
@@ -2036,7 +2056,7 @@ uint32_t get_dailyfx(uint32_t *prices)
|
||||
//{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"}
|
||||
char url[512],*datestr; cJSON *json,*rates; int32_t i; uint32_t datenum=0,price = 0;
|
||||
sprintf(url,"https://api.openrates.io/latest?base=USD");
|
||||
if ( (json= send_curl(url,(char *)"dailyfx")) != 0 )
|
||||
if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"dailyfx")) != 0 )
|
||||
{
|
||||
if ( (rates= jobj(json,(char *)"rates")) != 0 )
|
||||
{
|
||||
@@ -2059,7 +2079,7 @@ uint32_t get_binanceprice(const char *symbol)
|
||||
{
|
||||
char url[512]; cJSON *json; uint32_t price = 0;
|
||||
sprintf(url,"https://api.binance.com/api/v1/ticker/price?symbol=%sBTC",symbol);
|
||||
if ( (json= send_curl(url,(char *)"bnbprice")) != 0 )
|
||||
if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"bnbprice")) != 0 )
|
||||
{
|
||||
price = jdouble(json,(char *)"price")*SATOSHIDEN + 0.0000000049;
|
||||
free_json(json);
|
||||
@@ -2085,6 +2105,23 @@ int32_t get_cryptoprices(uint32_t *prices,const char *list[],int32_t n,std::vect
|
||||
return(-errs);
|
||||
}
|
||||
|
||||
/*uint32_t oldget_stockprice(const char *symbol)
|
||||
{
|
||||
char url[512]; cJSON *json,*obj; uint32_t high,low,price = 0;
|
||||
sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50);
|
||||
if ( (json= get_urljson(url)) != 0 )
|
||||
{
|
||||
if ( (obj= jobj(json,(char *)"Time Series (15min)")) != 0 )
|
||||
{
|
||||
high = jdouble(jitem(obj,0),(char *)"2. high")*10000 + 0.000049;
|
||||
low = jdouble(jitem(obj,0),(char *)"3. low")*10000 + 0.000049;
|
||||
price = (high + low) / 2;
|
||||
}
|
||||
free_json(json);
|
||||
}
|
||||
return(price);
|
||||
}
|
||||
|
||||
uint32_t get_currencyprice(const char *symbol)
|
||||
{
|
||||
char url[512]; cJSON *json,*obj; uint32_t price = 0;
|
||||
@@ -2109,7 +2146,7 @@ int32_t get_stocks(const char *list[],int32_t n)
|
||||
}
|
||||
fprintf(stderr," errs.%d\n",errs);
|
||||
return(-errs);
|
||||
}
|
||||
}*/
|
||||
|
||||
// parse the coindesk specific data. yes, if this changes, it will require an update. However, regardless if the format from the data source changes, then the code that extracts it must be changed. One way to mitigate this is to have a large variety of data sources so that there is only a very remote chance that all of them are not available. Certainly the data gathering needs to be made more robust, but it doesnt really affect the proof of concept for the decentralized trustless oracle. The trustlessness is achieved by having all nodes get the oracle data.
|
||||
|
||||
@@ -2159,16 +2196,26 @@ int32_t komodo_cbopretsize(uint64_t flags)
|
||||
if ( (ASSETCHAINS_CBOPRET & 2) != 0 )
|
||||
size += (sizeof(Forex)/sizeof(*Forex)) * sizeof(uint32_t);
|
||||
if ( (ASSETCHAINS_CBOPRET & 4) != 0 )
|
||||
size += (sizeof(Cryptos)/sizeof(*Cryptos) + ASSETCHAINS_PRICES.size())*sizeof(uint32_t);
|
||||
size += (sizeof(Cryptos)/sizeof(*Cryptos) + ASSETCHAINS_PRICES.size()) * sizeof(uint32_t);
|
||||
if ( (ASSETCHAINS_CBOPRET & 8) != 0 )
|
||||
size += (ASSETCHAINS_STOCKS.size() * sizeof(uint32_t));
|
||||
}
|
||||
return(size);
|
||||
}
|
||||
|
||||
extern uint256 Queued_reconsiderblock;
|
||||
|
||||
void komodo_cbopretupdate(int32_t forceflag)
|
||||
{
|
||||
static uint32_t lasttime,lastcrypto,lastbtc,pending;
|
||||
static uint32_t pricebits[4],cryptoprices[KOMODO_MAXPRICES],forexprices[sizeof(Forex)/sizeof(*Forex)];
|
||||
static uint32_t lasttime,lastbtc,pending;
|
||||
static uint32_t pricebits[4],pricebuf[KOMODO_MAXPRICES],forexprices[sizeof(Forex)/sizeof(*Forex)];
|
||||
int32_t size; uint32_t flags=0,now; CBlockIndex *pindex;
|
||||
if ( Queued_reconsiderblock != zeroid )
|
||||
{
|
||||
fprintf(stderr,"Queued_reconsiderblock %s\n",Queued_reconsiderblock.GetHex().c_str());
|
||||
komodo_reconsiderblock(Queued_reconsiderblock);
|
||||
Queued_reconsiderblock = zeroid;
|
||||
}
|
||||
if ( forceflag != 0 && pending != 0 )
|
||||
{
|
||||
while ( pending != 0 )
|
||||
@@ -2208,23 +2255,35 @@ void komodo_cbopretupdate(int32_t forceflag)
|
||||
{
|
||||
if ( forceflag != 0 || flags != 0 )
|
||||
{
|
||||
get_cryptoprices(cryptoprices,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos)),ASSETCHAINS_PRICES);
|
||||
get_cryptoprices(pricebuf,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos)),ASSETCHAINS_PRICES);
|
||||
if ( flags == 0 )
|
||||
komodo_PriceCache_shift();
|
||||
memcpy(&PriceCache[0][size/sizeof(uint32_t)],cryptoprices,(sizeof(Cryptos)/sizeof(*Cryptos)+ASSETCHAINS_PRICES.size()) * sizeof(uint32_t));
|
||||
memcpy(&PriceCache[0][size/sizeof(uint32_t)],pricebuf,(sizeof(Cryptos)/sizeof(*Cryptos)+ASSETCHAINS_PRICES.size()) * sizeof(uint32_t));
|
||||
flags |= 4; // very rarely we can see flags == 6 case
|
||||
}
|
||||
size += (sizeof(Cryptos)/sizeof(*Cryptos)+ASSETCHAINS_PRICES.size()) * sizeof(uint32_t);
|
||||
}
|
||||
now = (uint32_t)time(NULL);
|
||||
if ( (ASSETCHAINS_CBOPRET & 8) != 0 )
|
||||
{
|
||||
if ( forceflag != 0 || flags != 0 )
|
||||
{
|
||||
if ( get_stockprices(now,pricebuf,ASSETCHAINS_STOCKS) == ASSETCHAINS_STOCKS.size() )
|
||||
{
|
||||
if ( flags == 0 )
|
||||
komodo_PriceCache_shift();
|
||||
memcpy(&PriceCache[0][size/sizeof(uint32_t)],pricebuf,ASSETCHAINS_STOCKS.size() * sizeof(uint32_t));
|
||||
flags |= 8; // very rarely we can see flags == 10 case
|
||||
}
|
||||
}
|
||||
size += (ASSETCHAINS_STOCKS.size()) * sizeof(uint32_t);
|
||||
}
|
||||
if ( flags != 0 )
|
||||
{
|
||||
now = (uint32_t)time(NULL);
|
||||
if ( (flags & 1) != 0 )
|
||||
lastbtc = now;
|
||||
if ( (flags & 2) != 0 )
|
||||
lasttime = now;
|
||||
if ( (flags & 4) != 0 )
|
||||
lastcrypto = now;
|
||||
memcpy(Mineropret.data(),PriceCache[0],size);
|
||||
if ( ExtremePrice.dir != 0 && ExtremePrice.ind > 0 && ExtremePrice.ind < size/sizeof(uint32_t) && now < ExtremePrice.timestamp+3600 )
|
||||
{
|
||||
@@ -2244,19 +2303,6 @@ void komodo_cbopretupdate(int32_t forceflag)
|
||||
// fprintf(stderr,"%02x",Mineropret[i]);
|
||||
//fprintf(stderr," <- set Mineropret[%d] size.%d %ld\n",(int32_t)Mineropret.size(),size,sizeof(PriceCache[0]));
|
||||
}
|
||||
/*
|
||||
if ( (ASSETCHAINS_CBOPRET & 4) != 0 )
|
||||
{
|
||||
get_currencies(Metals,(int32_t)(sizeof(Metals)/sizeof(*Metals)));
|
||||
}
|
||||
if ( (ASSETCHAINS_CBOPRET & 32) != 0 )
|
||||
{
|
||||
get_stocks(Markets,(int32_t)(sizeof(Markets)/sizeof(*Markets)));
|
||||
}
|
||||
if ( (ASSETCHAINS_CBOPRET & 64) != 0 )
|
||||
{
|
||||
get_stocks(Techstocks,(int32_t)(sizeof(Techstocks)/sizeof(*Techstocks)));
|
||||
}*/
|
||||
}
|
||||
pending = 0;
|
||||
}
|
||||
@@ -2280,6 +2326,11 @@ int64_t komodo_pricemult(int32_t ind)
|
||||
for (j=0; j<sizeof(Cryptos)/sizeof(*Cryptos)+ASSETCHAINS_PRICES.size(); j++)
|
||||
PriceMult[i++] = 1;
|
||||
}
|
||||
if ( (ASSETCHAINS_CBOPRET & 8) != 0 )
|
||||
{
|
||||
for (j=0; j<ASSETCHAINS_STOCKS.size(); j++)
|
||||
PriceMult[i++] = 1000000;
|
||||
}
|
||||
}
|
||||
return(PriceMult[ind]);
|
||||
}
|
||||
@@ -2296,9 +2347,9 @@ char *komodo_pricename(char *name,int32_t ind)
|
||||
switch ( ind )
|
||||
{
|
||||
case 0: strcpy(name,"timestamp"); break;
|
||||
case 1: strcpy(name,"BTCUSD"); break;
|
||||
case 2: strcpy(name,"BTCGBP"); break;
|
||||
case 3: strcpy(name,"BTCEUR"); break;
|
||||
case 1: strcpy(name,"BTC_USD"); break;
|
||||
case 2: strcpy(name,"BTC_GBP"); break;
|
||||
case 3: strcpy(name,"BTC_EUR"); break;
|
||||
default: return(0); break;
|
||||
}
|
||||
return(name);
|
||||
@@ -2312,8 +2363,8 @@ char *komodo_pricename(char *name,int32_t ind)
|
||||
return(0);
|
||||
if ( ind < sizeof(Forex)/sizeof(*Forex) )
|
||||
{
|
||||
name[0] = 'U', name[1] = 'S', name[2] = 'D';
|
||||
strcpy(name+3,Forex[ind]);
|
||||
name[0] = 'U', name[1] = 'S', name[2] = 'D', name[3] = '_';
|
||||
strcpy(name+4,Forex[ind]);
|
||||
return(name);
|
||||
} else ind -= sizeof(Forex)/sizeof(*Forex);
|
||||
}
|
||||
@@ -2330,10 +2381,21 @@ char *komodo_pricename(char *name,int32_t ind)
|
||||
ind -= (sizeof(Cryptos)/sizeof(*Cryptos));
|
||||
strcpy(name,ASSETCHAINS_PRICES[ind].c_str());
|
||||
}
|
||||
strcat(name,"BTC");
|
||||
strcat(name,"_BTC");
|
||||
return(name);
|
||||
} else ind -= (sizeof(Cryptos)/sizeof(*Cryptos) + ASSETCHAINS_PRICES.size());
|
||||
}
|
||||
if ( (ASSETCHAINS_CBOPRET & 8) != 0 )
|
||||
{
|
||||
if ( ind < 0 )
|
||||
return(0);
|
||||
if ( ind < ASSETCHAINS_STOCKS.size() )
|
||||
{
|
||||
strcpy(name,ASSETCHAINS_STOCKS[ind].c_str());
|
||||
strcat(name,"_USD");
|
||||
return(name);
|
||||
} else ind -= ASSETCHAINS_STOCKS.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
@@ -2595,9 +2657,13 @@ int64_t komodo_priceave(int64_t *buf,int64_t *correlated,int32_t cskip)
|
||||
return((price*7 + halfave*5 + thirdave*3 + fourthave*2 + decayprice + buf[PRICES_DAYWINDOW-1]) / 19);
|
||||
}
|
||||
|
||||
void komodo_pricesinit()
|
||||
int32_t komodo_pricesinit()
|
||||
{
|
||||
int32_t i,createflag = 0;
|
||||
static int32_t didinit;
|
||||
int32_t i,num=0,createflag = 0;
|
||||
if ( didinit != 0 )
|
||||
return(-1);
|
||||
didinit = 1;
|
||||
boost::filesystem::path pricefname,pricesdir = GetDataDir() / "prices";
|
||||
fprintf(stderr,"pricesinit (%s)\n",pricesdir.string().c_str());
|
||||
if (!boost::filesystem::exists(pricesdir))
|
||||
@@ -2606,16 +2672,24 @@ void komodo_pricesinit()
|
||||
{
|
||||
if ( komodo_pricename(PRICES[i].symbol,i) == 0 )
|
||||
break;
|
||||
//fprintf(stderr,"%s.%d ",PRICES[i].symbol,i);
|
||||
if ( i == 0 )
|
||||
strcpy(PRICES[i].symbol,"rawprices");
|
||||
pricefname = pricesdir / PRICES[i].symbol;
|
||||
PRICES[i].fp = fopen(pricefname.string().c_str(), createflag != 0 ? "wb+" : "rb+");
|
||||
if ( createflag != 0 )
|
||||
PRICES[i].fp = fopen(pricefname.string().c_str(),"wb+");
|
||||
else if ( (PRICES[i].fp= fopen(pricefname.string().c_str(),"rb+")) == 0 )
|
||||
PRICES[i].fp = fopen(pricefname.string().c_str(),"wb+");
|
||||
if ( PRICES[i].fp != 0 )
|
||||
{
|
||||
fseek(PRICES[i].fp,(2*PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH) * sizeof(int64_t) * PRICES_MAXDATAPOINTS,SEEK_SET);
|
||||
fputc(0,PRICES[i].fp);
|
||||
fflush(PRICES[i].fp);
|
||||
}
|
||||
num++;
|
||||
if ( createflag != 0 )
|
||||
{
|
||||
fseek(PRICES[i].fp,(2*PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH) * sizeof(int64_t) * PRICES_MAXDATAPOINTS,SEEK_SET);
|
||||
fputc(0,PRICES[i].fp);
|
||||
fflush(PRICES[i].fp);
|
||||
}
|
||||
} else fprintf(stderr,"error opening %s createflag.%d\n",pricefname.string().c_str(), createflag);
|
||||
}
|
||||
if ( i > 0 && PRICES[0].fp != 0 && createflag != 0 )
|
||||
{
|
||||
@@ -2623,15 +2697,31 @@ void komodo_pricesinit()
|
||||
fputc(0,PRICES[0].fp);
|
||||
fflush(PRICES[0].fp);
|
||||
}
|
||||
fprintf(stderr,"pricesinit done i.%d num.%d numprices.%d\n",i,num,(int32_t)(komodo_cbopretsize(ASSETCHAINS_CBOPRET)/sizeof(uint32_t)));
|
||||
if ( i != num || i != komodo_cbopretsize(ASSETCHAINS_CBOPRET)/sizeof(uint32_t) )
|
||||
{
|
||||
fprintf(stderr,"fatal error opening prices files, start shutdown\n");
|
||||
StartShutdown();
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
pthread_mutex_t pricemutex;
|
||||
|
||||
// PRICES file layouts
|
||||
// [0] rawprice32 / timestamp
|
||||
// [1] correlated
|
||||
// [2] 24hr ave
|
||||
// [3] to [7] reserved
|
||||
|
||||
void komodo_pricesupdate(int32_t height,CBlock *pblock)
|
||||
{
|
||||
static int numprices; static uint32_t *ptr32; static int64_t *ptr64,*tmpbuf;
|
||||
int32_t ind,offset,width; int64_t correlated,smoothed; uint64_t seed,rngval; uint32_t rawprices[KOMODO_MAXPRICES],buf[4];
|
||||
int32_t ind,offset,width; int64_t correlated,smoothed; uint64_t seed,rngval; uint32_t rawprices[KOMODO_MAXPRICES],buf[PRICES_MAXDATAPOINTS*2];
|
||||
width = PRICES_DAYWINDOW;//(2*PRICES_DAYWINDOW + PRICES_SMOOTHWIDTH);
|
||||
if ( numprices == 0 )
|
||||
{
|
||||
pthread_mutex_init(&pricemutex,0);
|
||||
numprices = (int32_t)(komodo_cbopretsize(ASSETCHAINS_CBOPRET) / sizeof(uint32_t));
|
||||
ptr32 = (uint32_t *)calloc(sizeof(uint32_t),numprices * width);
|
||||
ptr64 = (int64_t *)calloc(sizeof(int64_t),PRICES_DAYWINDOW*PRICES_MAXDATAPOINTS);
|
||||
@@ -2645,6 +2735,7 @@ void komodo_pricesupdate(int32_t height,CBlock *pblock)
|
||||
//fprintf(stderr,"numprices.%d\n",numprices);
|
||||
if ( PRICES[0].fp != 0 )
|
||||
{
|
||||
pthread_mutex_lock(&pricemutex);
|
||||
fseek(PRICES[0].fp,height * numprices * sizeof(uint32_t),SEEK_SET);
|
||||
if ( fwrite(rawprices,sizeof(uint32_t),numprices,PRICES[0].fp) != numprices )
|
||||
fprintf(stderr,"error writing rawprices for ht.%d\n",height);
|
||||
@@ -2657,11 +2748,17 @@ void komodo_pricesupdate(int32_t height,CBlock *pblock)
|
||||
rngval = seed;
|
||||
for (ind=1; ind<numprices; ind++)
|
||||
{
|
||||
if ( PRICES[ind].fp == 0 )
|
||||
{
|
||||
fprintf(stderr,"PRICES[%d].fp is null\n",ind);
|
||||
continue;
|
||||
}
|
||||
offset = (width-1)*numprices + ind;
|
||||
rngval = (rngval*11109 + 13849);
|
||||
if ( (correlated= komodo_pricecorrelated(rngval,ind,&ptr32[offset],-numprices,0,PRICES_SMOOTHWIDTH)) > 0 )
|
||||
{
|
||||
fseek(PRICES[ind].fp,height * sizeof(int64_t) * PRICES_MAXDATAPOINTS,SEEK_SET);
|
||||
memset(buf,0,sizeof(buf));
|
||||
buf[0] = rawprices[ind];
|
||||
buf[1] = rawprices[0]; // timestamp
|
||||
memcpy(&buf[2],&correlated,sizeof(correlated));
|
||||
@@ -2670,7 +2767,7 @@ void komodo_pricesupdate(int32_t height,CBlock *pblock)
|
||||
else if ( height > PRICES_DAYWINDOW*2 )
|
||||
{
|
||||
fseek(PRICES[ind].fp,(height-PRICES_DAYWINDOW+1) * PRICES_MAXDATAPOINTS * sizeof(int64_t),SEEK_SET);
|
||||
if ( fread(ptr64,sizeof(int64_t),(PRICES_DAYWINDOW-1)*PRICES_MAXDATAPOINTS+2,PRICES[ind].fp) == (PRICES_DAYWINDOW-1)*PRICES_MAXDATAPOINTS+2 )
|
||||
if ( fread(ptr64,sizeof(int64_t),PRICES_DAYWINDOW*PRICES_MAXDATAPOINTS,PRICES[ind].fp) == PRICES_DAYWINDOW*PRICES_MAXDATAPOINTS )
|
||||
{
|
||||
if ( (smoothed= komodo_priceave(tmpbuf,&ptr64[(PRICES_DAYWINDOW-1)*PRICES_MAXDATAPOINTS+1],-PRICES_MAXDATAPOINTS)) > 0 )
|
||||
{
|
||||
@@ -2686,8 +2783,22 @@ void komodo_pricesupdate(int32_t height,CBlock *pblock)
|
||||
fprintf(stderr,"height.%d\n",height);
|
||||
} else fprintf(stderr,"error reading rawprices for ht.%d\n",height);
|
||||
} else fprintf(stderr,"height.%d <= width.%d\n",height,width);
|
||||
pthread_mutex_unlock(&pricemutex);
|
||||
} else fprintf(stderr,"null PRICES[0].fp\n");
|
||||
} else fprintf(stderr,"numprices mismatch\n");
|
||||
} else fprintf(stderr,"numprices mismatch, height.%d\n",height);
|
||||
}
|
||||
|
||||
int32_t komodo_priceget(int64_t *buf64,int32_t ind,int32_t height,int32_t numblocks)
|
||||
{
|
||||
FILE *fp; int32_t retval = PRICES_MAXDATAPOINTS;
|
||||
pthread_mutex_lock(&pricemutex);
|
||||
if ( ind < KOMODO_MAXPRICES && (fp= PRICES[ind].fp) != 0 )
|
||||
{
|
||||
fseek(fp,height * PRICES_MAXDATAPOINTS * sizeof(int64_t),SEEK_SET);
|
||||
if ( fread(buf64,sizeof(int64_t),numblocks*PRICES_MAXDATAPOINTS,fp) != numblocks*PRICES_MAXDATAPOINTS )
|
||||
retval = -1;
|
||||
}
|
||||
pthread_mutex_unlock(&pricemutex);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ struct komodo_state KOMODO_STATES[34];
|
||||
#define _COINBASE_MATURITY 100
|
||||
int COINBASE_MATURITY = _COINBASE_MATURITY;//100;
|
||||
unsigned int WITNESS_CACHE_SIZE = _COINBASE_MATURITY+10;
|
||||
|
||||
uint256 KOMODO_EARLYTXID;
|
||||
int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,IS_STAKED_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,STAKED_ERA,KOMODO_CONNECTING = -1,KOMODO_DEALERNODE,KOMODO_EXTRASATOSHI,ASSETCHAINS_FOUNDERS;
|
||||
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1;
|
||||
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,NOTARY_ADDRESS,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB;
|
||||
@@ -74,7 +74,7 @@ uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0,ASSETCHAIN
|
||||
uint64_t ASSETCHAINS_LASTERA = 1;
|
||||
uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS];
|
||||
uint8_t ASSETCHAINS_CCDISABLES[256];
|
||||
std::vector<std::string> ASSETCHAINS_PRICES;
|
||||
std::vector<std::string> ASSETCHAINS_PRICES,ASSETCHAINS_STOCKS;
|
||||
|
||||
#define _ASSETCHAINS_EQUIHASH 0
|
||||
uint32_t ASSETCHAINS_NUMALGOS = 3;
|
||||
@@ -109,6 +109,8 @@ uint64_t PENDING_KOMODO_TX;
|
||||
extern int32_t KOMODO_LOADINGBLOCKS;
|
||||
unsigned int MAX_BLOCK_SIGOPS = 20000;
|
||||
|
||||
int32_t KOMODO_TESTNODE;
|
||||
|
||||
struct komodo_kv *KOMODO_KV;
|
||||
pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex;
|
||||
|
||||
|
||||
7
src/komodo_nk.h
Normal file
7
src/komodo_nk.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef KOMODO_NK_H
|
||||
#define KOMODO_NK_H
|
||||
|
||||
#define ASSETCHAINS_N 96
|
||||
#define ASSETCHAINS_K 5
|
||||
|
||||
#endif
|
||||
@@ -1667,6 +1667,28 @@ extern int64_t MAX_MONEY;
|
||||
void komodo_cbopretupdate(int32_t forceflag);
|
||||
void SplitStr(const std::string& strVal, std::vector<std::string> &outVals);
|
||||
|
||||
int8_t equihash_params_possible(uint64_t n, uint64_t k)
|
||||
{
|
||||
/* To add more of these you also need to edit:
|
||||
* equihash.cpp very end of file with the tempate to point to the new param numbers
|
||||
* equihash.h
|
||||
* line 210/217 (declaration of equihash class)
|
||||
* Add this object to the following functions:
|
||||
* EhInitialiseState
|
||||
* EhBasicSolve
|
||||
* EhOptimisedSolve
|
||||
* EhIsValidSolution
|
||||
* Alternatively change ASSETCHAINS_N and ASSETCHAINS_K in komodo_nk.h for fast testing.
|
||||
*/
|
||||
if ( k == 9 && (n == 200 || n == 210) )
|
||||
return(0);
|
||||
if ( k == 5 && (n == 150 || n == 144 || n == 96 || n == 48) )
|
||||
return(0);
|
||||
if ( k == ASSETCHAINS_K && n == ASSETCHAINS_N)
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
void komodo_args(char *argv0)
|
||||
{
|
||||
extern const char *Notaries_elected1[][2];
|
||||
@@ -1675,7 +1697,7 @@ void komodo_args(char *argv0)
|
||||
IS_STAKED_NOTARY = GetArg("-stakednotary", -1);
|
||||
if ( IS_STAKED_NOTARY != -1 && IS_KOMODO_NOTARY == true ) {
|
||||
fprintf(stderr, "Cannot be STAKED and KMD notary at the same time!\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
memset(ccenables,0,sizeof(ccenables));
|
||||
memset(disablebits,0,sizeof(disablebits));
|
||||
@@ -1688,6 +1710,7 @@ void komodo_args(char *argv0)
|
||||
DONATION_PUBKEY = GetArg("-donation", "");
|
||||
NOTARY_PUBKEY = GetArg("-pubkey", "");
|
||||
KOMODO_DEALERNODE = GetArg("-dealer",0);
|
||||
KOMODO_TESTNODE = GetArg("-testnode",0);
|
||||
if ( strlen(NOTARY_PUBKEY.c_str()) == 66 )
|
||||
{
|
||||
decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str());
|
||||
@@ -1729,10 +1752,12 @@ void komodo_args(char *argv0)
|
||||
ASSETCHAINS_BLOCKTIME = GetArg("-ac_blocktime",60);
|
||||
ASSETCHAINS_PUBLIC = GetArg("-ac_public",0);
|
||||
ASSETCHAINS_PRIVATE = GetArg("-ac_private",0);
|
||||
Split(GetArg("-ac_nk",""), ASSETCHAINS_NK, 0);
|
||||
if ( (KOMODO_REWIND= GetArg("-rewind",0)) != 0 )
|
||||
{
|
||||
printf("KOMODO_REWIND %d\n",KOMODO_REWIND);
|
||||
}
|
||||
KOMODO_EARLYTXID = Parseuint256(GetArg("-earlytxid","0").c_str());
|
||||
if ( name.c_str()[0] != 0 )
|
||||
{
|
||||
std::string selectedAlgo = GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0]));
|
||||
@@ -1749,6 +1774,14 @@ void komodo_args(char *argv0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH && ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0 )
|
||||
{
|
||||
if ( equihash_params_possible(ASSETCHAINS_NK[0], ASSETCHAINS_NK[1]) == -1 )
|
||||
{
|
||||
printf("equihash values N.%li and K.%li are not currently available\n", ASSETCHAINS_NK[0], ASSETCHAINS_NK[1]);
|
||||
exit(0);
|
||||
} else printf("ASSETCHAINS_ALGO, algorithm set to equihash with N.%li and K.%li\n", ASSETCHAINS_NK[0], ASSETCHAINS_NK[1]);
|
||||
}
|
||||
if (i == ASSETCHAINS_NUMALGOS)
|
||||
{
|
||||
printf("ASSETCHAINS_ALGO, %s not supported. using equihash\n", selectedAlgo.c_str());
|
||||
@@ -1800,7 +1833,7 @@ void komodo_args(char *argv0)
|
||||
if ( ASSETCHAINS_SUPPLY > (uint64_t)90*1000*1000000 )
|
||||
{
|
||||
fprintf(stderr,"-ac_supply must be less than 90 billion\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
fprintf(stderr,"ASSETCHAINS_SUPPLY %llu\n",(long long)ASSETCHAINS_SUPPLY);
|
||||
|
||||
@@ -1815,11 +1848,17 @@ void komodo_args(char *argv0)
|
||||
if ( ASSETCHAINS_CBOPRET != 0 )
|
||||
{
|
||||
SplitStr(GetArg("-ac_prices",""), ASSETCHAINS_PRICES);
|
||||
for (i=0; i<ASSETCHAINS_PRICES.size(); i++)
|
||||
fprintf(stderr,"%s ",ASSETCHAINS_PRICES[i].c_str());
|
||||
if ( ASSETCHAINS_PRICES.size() > 0 )
|
||||
ASSETCHAINS_CBOPRET |= 4;
|
||||
SplitStr(GetArg("-ac_stocks",""), ASSETCHAINS_STOCKS);
|
||||
if ( ASSETCHAINS_STOCKS.size() > 0 )
|
||||
ASSETCHAINS_CBOPRET |= 8;
|
||||
for (i=0; i<ASSETCHAINS_PRICES.size(); i++)
|
||||
fprintf(stderr,"%s ",ASSETCHAINS_PRICES[i].c_str());
|
||||
fprintf(stderr,"%d -ac_prices\n",(int32_t)ASSETCHAINS_PRICES.size());
|
||||
for (i=0; i<ASSETCHAINS_STOCKS.size(); i++)
|
||||
fprintf(stderr,"%s ",ASSETCHAINS_STOCKS[i].c_str());
|
||||
fprintf(stderr,"%d -ac_stocks\n",(int32_t)ASSETCHAINS_STOCKS.size());
|
||||
}
|
||||
hexstr = GetArg("-ac_mineropret","");
|
||||
if ( hexstr.size() != 0 )
|
||||
@@ -1833,7 +1872,7 @@ void komodo_args(char *argv0)
|
||||
if ( ASSETCHAINS_COMMISSION != 0 && ASSETCHAINS_FOUNDERS_REWARD != 0 )
|
||||
{
|
||||
fprintf(stderr,"cannot use founders reward and commission on the same chain.\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
if ( ASSETCHAINS_CC != 0 )
|
||||
{
|
||||
@@ -1873,7 +1912,7 @@ void komodo_args(char *argv0)
|
||||
if ( ASSETCHAINS_BEAMPORT != 0 && ASSETCHAINS_CODAPORT != 0 )
|
||||
{
|
||||
fprintf(stderr,"can only have one of -ac_beam or -ac_coda\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
ASSETCHAINS_SELFIMPORT = GetArg("-ac_import",""); // BEAM, CODA, PUBKEY, GATEWAY
|
||||
if ( ASSETCHAINS_SELFIMPORT == "PUBKEY" )
|
||||
@@ -1881,21 +1920,26 @@ void komodo_args(char *argv0)
|
||||
if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) != 66 )
|
||||
{
|
||||
fprintf(stderr,"invalid -ac_pubkey for -ac_import=PUBKEY\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
}
|
||||
else if ( ASSETCHAINS_SELFIMPORT == "BEAM" && ASSETCHAINS_BEAMPORT == 0 )
|
||||
{
|
||||
fprintf(stderr,"missing -ac_beam for BEAM rpcport\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
else if ( ASSETCHAINS_SELFIMPORT == "CODA" && ASSETCHAINS_CODAPORT == 0 )
|
||||
{
|
||||
fprintf(stderr,"missing -ac_coda for CODA rpcport\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
// else it can be gateway coin
|
||||
|
||||
else if (!ASSETCHAINS_SELFIMPORT.empty() && (ASSETCHAINS_ENDSUBSIDY[0]!=1 || ASSETCHAINS_SUPPLY>10 || ASSETCHAINS_COMMISSION!=0))
|
||||
{
|
||||
fprintf(stderr,"when using gateway import these must be set: -ac_end=1 -ac_supply=0 -ac_perc=0\n");
|
||||
StartShutdown();
|
||||
}
|
||||
|
||||
|
||||
if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 )
|
||||
ASSETCHAINS_STAKED = 100;
|
||||
@@ -1920,12 +1964,12 @@ void komodo_args(char *argv0)
|
||||
if ( ASSETCHAINS_SUPPLY > 10000000000 )
|
||||
{
|
||||
printf("ac_pubkey or ac_script wont work with ac_supply over 10 billion\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
if ( ASSETCHAINS_NOTARY_PAY[0] != 0 )
|
||||
{
|
||||
printf("Assetchains NOTARY PAY cannot be used with ac_pubkey or ac_script.\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 )
|
||||
{
|
||||
@@ -1966,9 +2010,9 @@ void komodo_args(char *argv0)
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 && ASSETCHAINS_MARMARA != 0 )
|
||||
{
|
||||
fprintf(stderr,"-ac_script and -ac_marmara are mutually exclusive\n");
|
||||
exit(0);
|
||||
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 )
|
||||
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) )
|
||||
{
|
||||
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;
|
||||
@@ -2085,9 +2129,24 @@ void komodo_args(char *argv0)
|
||||
extralen += symbol.size();
|
||||
}
|
||||
}
|
||||
if ( ASSETCHAINS_STOCKS.size() != 0 )
|
||||
{
|
||||
for (i=0; i<ASSETCHAINS_STOCKS.size(); i++)
|
||||
{
|
||||
symbol = ASSETCHAINS_STOCKS[i];
|
||||
memcpy(&extraptr[extralen],(char *)symbol.c_str(),symbol.size());
|
||||
extralen += symbol.size();
|
||||
}
|
||||
}
|
||||
//komodo_pricesinit();
|
||||
komodo_cbopretupdate(1); // will set Mineropret
|
||||
fprintf(stderr,"This blockchain uses data produced from CoinDesk Bitcoin Price Index\n");
|
||||
}
|
||||
if ( ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0 )
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
addn = GetArg("-seednode","");
|
||||
@@ -2134,7 +2193,7 @@ void komodo_args(char *argv0)
|
||||
if ( strcmp(ASSETCHAINS_SYMBOL,"KMD") == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant have assetchain named KMD\n");
|
||||
exit(0);
|
||||
StartShutdown();
|
||||
}
|
||||
if ( (port= komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL)) != 0 )
|
||||
ASSETCHAINS_RPCPORT = port;
|
||||
@@ -2216,6 +2275,11 @@ void komodo_args(char *argv0)
|
||||
}
|
||||
else if ( strcmp("VRSC",ASSETCHAINS_SYMBOL) == 0 )
|
||||
dpowconfs = 0;
|
||||
else if ( ASSETCHAINS_PRIVATE != 0 )
|
||||
{
|
||||
fprintf(stderr,"-ac_private for a non-PIRATE chain is not supported. The only reason to have an -ac_private chain is for total privacy and that is best achieved with the largest anon set. PIRATE has that and it is recommended to just use PIRATE\n");
|
||||
StartShutdown();
|
||||
}
|
||||
} else BITCOIND_RPCPORT = GetArg("-rpcport", BaseParams().RPCPort());
|
||||
KOMODO_DPOWCONFS = GetArg("-dpowconfs",dpowconfs);
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || strcmp(ASSETCHAINS_SYMBOL,"SUPERNET") == 0 || strcmp(ASSETCHAINS_SYMBOL,"DEX") == 0 || strcmp(ASSETCHAINS_SYMBOL,"COQUI") == 0 || strcmp(ASSETCHAINS_SYMBOL,"PIRATE") == 0 || strcmp(ASSETCHAINS_SYMBOL,"KMDICE") == 0 )
|
||||
|
||||
34
src/main.cpp
34
src/main.cpp
@@ -512,6 +512,8 @@ namespace {
|
||||
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
|
||||
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
|
||||
// download that next block if the window were 1 larger.
|
||||
if ( ASSETCHAINS_CBOPRET != 0 && IsInitialBlockDownload() == 0 )
|
||||
BLOCK_DOWNLOAD_WINDOW = 1;
|
||||
int nWindowEnd = state->pindexLastCommonBlock->GetHeight() + BLOCK_DOWNLOAD_WINDOW;
|
||||
int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->GetHeight(), nWindowEnd + 1);
|
||||
NodeId waitingfor = -1;
|
||||
@@ -794,7 +796,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight)
|
||||
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
|
||||
reason = "bare-multisig";
|
||||
return false;
|
||||
} else if (txout.scriptPubKey.IsPayToCryptoCondition() == 0 && txout.IsDust(::minRelayTxFee)) {
|
||||
} else if (whichType != TX_CRYPTOCONDITION && txout.IsDust(::minRelayTxFee)) {
|
||||
reason = "dust";
|
||||
return false;
|
||||
}
|
||||
@@ -978,7 +980,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
|
||||
* Ensure that a coinbase transaction is structured according to the consensus rules of the
|
||||
* chain
|
||||
*/
|
||||
bool ContextualCheckCoinbaseTransaction(const CBlock *block,CBlockIndex * const previndex,const CTransaction& tx, const int nHeight)
|
||||
bool ContextualCheckCoinbaseTransaction(const CBlock *block,CBlockIndex * const previndex,const CTransaction& tx, const int nHeight,int32_t validateprices)
|
||||
{
|
||||
// if time locks are on, ensure that this coin base is time locked exactly as it should be
|
||||
if (((uint64_t)(tx.GetValueOut()) >= ASSETCHAINS_TIMELOCKGTE) ||
|
||||
@@ -1019,7 +1021,7 @@ bool ContextualCheckCoinbaseTransaction(const CBlock *block,CBlockIndex * const
|
||||
{
|
||||
|
||||
}
|
||||
else if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 && tx.vout.size() > 0 )
|
||||
else if ( ASSETCHAINS_CBOPRET != 0 && validateprices != 0 && nHeight > 0 && tx.vout.size() > 0 )
|
||||
{
|
||||
if ( komodo_opretvalidate(block,previndex,nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 )
|
||||
return(false);
|
||||
@@ -1041,7 +1043,7 @@ bool ContextualCheckTransaction(const CBlock *block, CBlockIndex * const prevind
|
||||
CValidationState &state,
|
||||
const int nHeight,
|
||||
const int dosLevel,
|
||||
bool (*isInitBlockDownload)())
|
||||
bool (*isInitBlockDownload)(),int32_t validateprices)
|
||||
{
|
||||
bool overwinterActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
|
||||
bool saplingActive = NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING);
|
||||
@@ -1172,7 +1174,7 @@ bool ContextualCheckTransaction(const CBlock *block, CBlockIndex * const prevind
|
||||
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
if (!ContextualCheckCoinbaseTransaction(block,previndex,tx, nHeight))
|
||||
if (!ContextualCheckCoinbaseTransaction(block,previndex,tx, nHeight,validateprices))
|
||||
return state.DoS(100, error("CheckTransaction(): invalid script data for coinbase time lock"),
|
||||
REJECT_INVALID, "bad-txns-invalid-script-data-for-coinbase-time-lock");
|
||||
}
|
||||
@@ -1677,7 +1679,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
}
|
||||
// DoS level set to 10 to be more forgiving.
|
||||
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
|
||||
if (!fSkipExpiry && !ContextualCheckTransaction(0,0,tx, state, nextBlockHeight, (dosLevel == -1) ? 10 : dosLevel))
|
||||
if (!fSkipExpiry && !ContextualCheckTransaction(0,0,tx, state, nextBlockHeight, (dosLevel == -1) ? 10 : dosLevel,0))
|
||||
{
|
||||
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
|
||||
}
|
||||
@@ -3306,7 +3308,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
REJECT_INVALID, "bad-cb-amount");
|
||||
// calculate the notaries compensation and validate the amounts and pubkeys are correct.
|
||||
uint64_t notarypaycheque = komodo_checknotarypay((CBlock *)&block,(int32_t)pindex->GetHeight());
|
||||
fprintf(stderr, "notarypaycheque.%lu\n", notarypaycheque);
|
||||
//fprintf(stderr, "notarypaycheque.%lu\n", notarypaycheque);
|
||||
if ( notarypaycheque > 0 )
|
||||
blockReward += notarypaycheque;
|
||||
else
|
||||
@@ -5271,6 +5273,8 @@ bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidat
|
||||
return true;
|
||||
}
|
||||
|
||||
uint256 Queued_reconsiderblock;
|
||||
|
||||
bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
@@ -5331,6 +5335,18 @@ bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, C
|
||||
fprintf(stderr,"saplinght.%d tipht.%d blockht.%d cmp.%d\n",saplinght,(int32_t)tmpptr->GetHeight(),pindex->GetHeight(),pindex->GetHeight() < 0 || (pindex->GetHeight() >= saplinght && pindex->GetHeight() < saplinght+50000) || (tmpptr->GetHeight() > saplinght-720 && tmpptr->GetHeight() < saplinght+720));
|
||||
if ( pindex->GetHeight() < 0 || (pindex->GetHeight() >= saplinght && pindex->GetHeight() < saplinght+50000) || (tmpptr->GetHeight() > saplinght-720 && tmpptr->GetHeight() < saplinght+720) )
|
||||
*futureblockp = 1;
|
||||
if ( ASSETCHAINS_CBOPRET != 0 )
|
||||
{
|
||||
CValidationState tmpstate; CBlockIndex *tmpindex; int32_t ht,longest;
|
||||
ht = (int32_t)pindex->GetHeight();
|
||||
longest = komodo_longestchain();
|
||||
if ( (longest == 0 || ht < longest-6) && (tmpindex=komodo_chainactive(ht)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"reconsider height.%d, longest.%d\n",(int32_t)ht,longest);
|
||||
if ( Queued_reconsiderblock == zeroid )
|
||||
Queued_reconsiderblock = pindex->GetBlockHash();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( *futureblockp == 0 )
|
||||
{
|
||||
@@ -6397,8 +6413,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
|
||||
nLoaded++;
|
||||
if (state.IsError())
|
||||
break;
|
||||
} else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->GetHeight() % 1000 == 0) {
|
||||
LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->GetHeight());
|
||||
} else if (hash != chainparams.GetConsensus().hashGenesisBlock && komodo_blockheight(hash) % 1000 == 0) {
|
||||
LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), komodo_blockheight(hash));
|
||||
}
|
||||
|
||||
// Recursively process earlier encountered successors of this block
|
||||
|
||||
@@ -111,7 +111,7 @@ static const unsigned int MAX_HEADERS_RESULTS = 160;
|
||||
* Larger windows tolerate larger download speed differences between peer, but increase the potential
|
||||
* degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning
|
||||
* harder). We'll probably want to make this a per-peer adaptive value at some point. */
|
||||
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
|
||||
static unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
|
||||
/** Time to wait (in seconds) between writing blocks/block index to disk. */
|
||||
static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
|
||||
/** Time to wait (in seconds) between flushing chainstate to disk. */
|
||||
@@ -707,7 +707,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
|
||||
|
||||
/** Check a transaction contextually against a set of consensus rules */
|
||||
bool ContextualCheckTransaction(const CBlock *block, CBlockIndex * const pindexPrev,const CTransaction& tx, CValidationState &state, int nHeight, int dosLevel,
|
||||
bool (*isInitBlockDownload)() = IsInitialBlockDownload);
|
||||
bool (*isInitBlockDownload)() = IsInitialBlockDownload,int32_t validateprices=1);
|
||||
|
||||
/** Apply the effects of this transaction on the UTXO set represented by view */
|
||||
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
|
||||
|
||||
@@ -224,7 +224,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
|
||||
CBlockIndex* pindexPrev = 0;
|
||||
{
|
||||
LOCK2(cs_main,mempool.cs);
|
||||
ENTER_CRITICAL_SECTION(cs_main);
|
||||
ENTER_CRITICAL_SECTION(mempool.cs);
|
||||
pindexPrev = chainActive.LastTip();
|
||||
const int nHeight = pindexPrev->GetHeight() + 1;
|
||||
const Consensus::Params &consensusParams = chainparams.GetConsensus();
|
||||
@@ -370,7 +371,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
}
|
||||
dPriority += (double)nValueIn * nConf;
|
||||
}
|
||||
if ( numSN != 0 && TMP_NotarisationNotaries.size() >= numSN / 5 )
|
||||
if ( numSN != 0 && notarypubkeys[0][0] != 0 && TMP_NotarisationNotaries.size() >= numSN / 5 )
|
||||
{
|
||||
// check a notary didnt sign twice (this would be an invalid notarisation later on and cause problems)
|
||||
std::set<int> checkdupes( TMP_NotarisationNotaries.begin(), TMP_NotarisationNotaries.end() );
|
||||
@@ -417,7 +418,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
NotarisationNotaries = TMP_NotarisationNotaries;
|
||||
dPriority = 1e16;
|
||||
fNotarisationBlock = true;
|
||||
fprintf(stderr, "Notarisation %s set to maximum priority\n",hash.ToString().c_str());
|
||||
//fprintf(stderr, "Notarisation %s set to maximum priority\n",hash.ToString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,10 +564,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
//LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x stake.%i\n", nBlockSize,blocktime,pblock->nBits,isStake);
|
||||
if ( ASSETCHAINS_SYMBOL[0] != 0 && isStake )
|
||||
{
|
||||
uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[512],*ptr;
|
||||
CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), stakeHeight);
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[512],*ptr;
|
||||
CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), stakeHeight);
|
||||
|
||||
if (ASSETCHAINS_LWMAPOS != 0)
|
||||
{
|
||||
uint32_t nBitsPOS;
|
||||
@@ -591,7 +593,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
{
|
||||
sleep(1);
|
||||
if ( (rand() % 100) < 1 )
|
||||
fprintf(stderr, "%u seconds until elegible, waiting...\n", blocktime-((uint32_t)GetAdjustedTime()+57));
|
||||
fprintf(stderr, "%u seconds until elegible, waiting.\n", blocktime-((uint32_t)GetAdjustedTime()+57));
|
||||
if ( chainActive.LastTip()->GetHeight() >= stakeHeight )
|
||||
{
|
||||
fprintf(stderr, "Block Arrived, reset staking loop.\n");
|
||||
@@ -601,8 +603,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
ENTER_CRITICAL_SECTION(cs_main);
|
||||
ENTER_CRITICAL_SECTION(mempool.cs);
|
||||
|
||||
if ( siglen > 0 )
|
||||
{
|
||||
CAmount txfees;
|
||||
@@ -615,7 +616,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
nFees += txfees;
|
||||
pblock->nTime = blocktime;
|
||||
//printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeight()+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13)));
|
||||
} else return(0); //fprintf(stderr,"no utxos eligible for staking\n");
|
||||
} else return(0); //fprintf(stderr,"no utxos eligible for staking\n");
|
||||
}
|
||||
|
||||
// Create coinbase tx
|
||||
@@ -687,6 +688,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
if (scriptPubKeyIn.IsPayToScriptHash() || scriptPubKeyIn.IsPayToCryptoCondition())
|
||||
{
|
||||
fprintf(stderr,"CreateNewBlock: attempt to add timelock to pay2sh or pay2cc\n");
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
|
||||
{
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -708,6 +714,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
if ( totalsats == 0 )
|
||||
{
|
||||
fprintf(stderr, "Could not create notary payment, trying again.\n");
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
|
||||
{
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
fprintf(stderr, "Created notary payment coinbase totalsat.%lu\n",totalsats);
|
||||
@@ -778,6 +789,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"error adding notaryvin, need to create 0.0001 utxos\n");
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
|
||||
{
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
@@ -792,6 +808,11 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
|
||||
//fprintf(stderr,"valid\n");
|
||||
}
|
||||
}
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
|
||||
{
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
}
|
||||
//fprintf(stderr,"done new block\n");
|
||||
return pblocktemplate.release();
|
||||
}
|
||||
@@ -1587,9 +1608,10 @@ void static BitcoinMiner()
|
||||
if ( notaryid != My_notaryid )
|
||||
My_notaryid = notaryid;
|
||||
std::string solver;
|
||||
//if ( notaryid >= 0 || ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
solver = "tromp";
|
||||
//else solver = "default";
|
||||
if ( ASSETCHAINS_NK[0] == 0 && ASSETCHAINS_NK[1] == 0 )
|
||||
solver = "tromp";
|
||||
else
|
||||
solver = "default";
|
||||
assert(solver == "tromp" || solver == "default");
|
||||
LogPrint("pow", "Using Equihash solver \"%s\" with n = %u, k = %u\n", solver, n, k);
|
||||
if ( ASSETCHAINS_SYMBOL[0] != 0 )
|
||||
@@ -1930,11 +1952,11 @@ void static BitcoinMiner()
|
||||
ehSolverRuns.increment();
|
||||
if (found) {
|
||||
int32_t i; uint256 hash = pblock->GetHash();
|
||||
for (i=0; i<32; i++)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
|
||||
fprintf(stderr," <- %s Block found %d\n",ASSETCHAINS_SYMBOL,Mining_height);
|
||||
FOUND_BLOCK = 1;
|
||||
KOMODO_MAYBEMINED = Mining_height;
|
||||
//for (i=0; i<32; i++)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
|
||||
//fprintf(stderr," <- %s Block found %d\n",ASSETCHAINS_SYMBOL,Mining_height);
|
||||
//FOUND_BLOCK = 1;
|
||||
//KOMODO_MAYBEMINED = Mining_height;
|
||||
break;
|
||||
}
|
||||
} catch (EhSolverCancelledException&) {
|
||||
@@ -1947,12 +1969,12 @@ void static BitcoinMiner()
|
||||
// Check for stop or if block needs to be rebuilt
|
||||
boost::this_thread::interruption_point();
|
||||
// Regtest mode doesn't require peers
|
||||
if ( FOUND_BLOCK != 0 )
|
||||
/*if ( FOUND_BLOCK != 0 )
|
||||
{
|
||||
FOUND_BLOCK = 0;
|
||||
fprintf(stderr,"FOUND_BLOCK!\n");
|
||||
//sleep(2000);
|
||||
}
|
||||
} */
|
||||
if (vNodes.empty() && chainparams.MiningRequiresPeers())
|
||||
{
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || Mining_height > ASSETCHAINS_MINHEIGHT )
|
||||
|
||||
@@ -23,8 +23,8 @@ static const char *iguanaSeeds[8][1] =
|
||||
static const int STAKED_ERA_GAP = 777;
|
||||
|
||||
static const int NUM_STAKED_ERAS = 4;
|
||||
static const int STAKED_NOTARIES_TIMESTAMP[NUM_STAKED_ERAS] = {1542964044, 1549188000, 1604233333, 1604244444};
|
||||
static const int32_t num_notaries_STAKED[NUM_STAKED_ERAS] = { 17, 25, 19, 17 };
|
||||
static const int STAKED_NOTARIES_TIMESTAMP[NUM_STAKED_ERAS] = {1604244444, 1604244444, 1604244444, 1604244444};
|
||||
static const int32_t num_notaries_STAKED[NUM_STAKED_ERAS] = { 20, 25, 19, 17 };
|
||||
|
||||
// Era array of pubkeys.
|
||||
static const char *notaries_STAKED[NUM_STAKED_ERAS][64][2] =
|
||||
@@ -33,20 +33,23 @@ static const char *notaries_STAKED[NUM_STAKED_ERAS][64][2] =
|
||||
{"blackjok3r", "021914947402d936a89fbdd1b12be49eb894a1568e5e17bb18c8a6cffbd3dc106e" }, // RTVti13NP4eeeZaCCmQxc2bnPdHxCJFP9x
|
||||
{"alright", "0285657c689b903218c97f5f10fe1d10ace2ed6595112d9017f54fb42ea1c1dda8" }, //RXmXeQ8LfJK6Y1aTM97cRz9Gu5f6fmR3sg
|
||||
{"webworker01", "031d1fb39ae4dca28965c3abdbd21faa0f685f6d7b87a60561afa7c448343fef6d" }, //RGsQiArk5sTmjXZV9UzGMW5njyvtSnsTN8
|
||||
{"CrisF", "03f87f1bccb744d90fdbf7fad1515a98e9fc7feb1800e460d2e7565b88c3971bf3" }, //RMwEpnaVe3cesWbMqqKYPPkaLcDkooTDgZ
|
||||
{"smk762", "02eacef682d2f86e0103c18f4da46116e17196f3fb8f73ed931acb78e81d8e1aa5" }, // RQVvzJ8gepCDVjhqCAc5Tia1kTmt8KDPL9
|
||||
{"jorian", "02150c410a606b898bcab4f083e48e0f98a510e0d48d4db367d37f318d26ae72e3" }, // RFgzxZe2P4RWKx6E9QGPK3rx3TXeWxSqa8
|
||||
{"CrisF", "024d19acf0d5de212cdd50326cd143292545d366a71b2b9c6df9f2110de2dfa1f2" }, // RKtAD2kyRRMx4EiG1eeTNprF5h2nmGbzzu
|
||||
{"smk762", "029f6c1f38c4d6825acb3b4b5147f7992e943b617cdaa0f4f5f36187e239d52d5a" }, // RPy6Xj2LWrxNoEW9YyREDgBZDZZ5qURXBU
|
||||
{"jorian", "0288e682c1ac449f1b85c4acb2d0bcd216d5df34c15fd18b8a8dd5fa64b8ece8ef" }, // RR1yT5aB19VwFoUCGTW4q4pk4qmhHEEE4t
|
||||
{"TonyL", "021a559101e355c907d9c553671044d619769a6e71d624f68bfec7d0afa6bd6a96" }, // RHq3JsvLxU45Z8ufYS6RsDpSG4wi6ucDev
|
||||
{"Emman", "038f642dcdacbdf510b7869d74544dbc6792548d9d1f8d73a999dd9f45f513c935" }, //RN2KsQGW36Ah4NorJDxLJp2xiYJJEzk9Y6
|
||||
{"CHMEX", "03ed125d1beb118d12ff0a052bdb0cee32591386d718309b2924f2c36b4e7388e6" }, // RF4HiVeuYpaznRPs7fkRAKKYqT5tuxQQTL
|
||||
{"metaphilibert", "0344182c376f054e3755d712361672138660bda8005abb64067eb5aa98bdb40d10" }, // RG28QSnYFADBg1dAVkH1uPGYS6F8ioEUM2
|
||||
{"greentea", "02054c14ae81838a063d22a75eaa3c961415f6825a57c8b8e4148d19dad64f128e" }, // REF7R76WpL1v7nSXjjiNHtRa2xYtq5qk1p
|
||||
{"CMaurice", "025830ce81bd1301fb67d5872344efa7a9ff99ae85fe1234f18c085db9072b740f" }, // RX7pXUaV24xFn6DVKV8t3PrRF3gKw6TBjf
|
||||
{"Bar_F1sh_Rel", "0395f2d9dd9ccb78caf74bff49b6d959afb95af746462e1b35f4a167d8e82b3666" }, // RBbLxJagCA9QHDazQvfnDZe874V1K4Gu8t
|
||||
{"jusoaresf", "02dfb7ed72a23f6d07f0ea2f28192ee174733cc8412ec0f97b073007b78fab6346" }, // RBQGfE5Hxsjm1BPraTxbneRuNasPDuoLnu
|
||||
{"zatJUM", "030fff499b6dc0215344b28a0b6b4becdfb00cd34cd1b36b983ec14f47965fd4bc" }, // RSoEDLBasth7anxS8gbkg6KgeGiz8rhqv1
|
||||
{"dwy", "03669457b2934d98b5761121dd01b243aed336479625b293be9f8c43a6ae7aaeff" }, // RKhZMqRF361FSGFAzstP5AhozekPjoVh5q
|
||||
{"gcharang", "03336ca9db27cb6e882830e20dc525884e27dc94d557a5e68b972a5cbf9e8c62a8" }, // RJYiWn3FRCSSLf9Pe5RJcbrKQYosaMburP
|
||||
{"computergenie", "027313dabde94fb72f823231d0a1c59fc7baa2e5b3bb2af97ca7d70aae116026b9" }, // RLabsCGxTRqJcJvz6foKuXAB61puJ2x8yt
|
||||
{"daemonfox", "0383484bdc745b2b953c85b5a0c496a1f27bc42ae971f15779ed1532421b3dd943" }, //
|
||||
{"SHossain", "02791f5c215b8a19c143a98e3371ff03b5613df9ac430c4a331ca55fed5761c800" }, // RKdLoHkyeorXmMtj91B1AAnAGiwsdt9MdF
|
||||
{"Nabob", "03ee91c20b6d26e3604022f42df6bb8de6f669da4591f93b568778cba13d9e9ddf" }, // RRwCLPZDzpHEFJnLev4phy51e2stHRUAaU
|
||||
{"mylo", "03f6b7fcaf0b8b8ec432d0de839a76598b78418dadd50c8e5594c0e557d914ec09" }, // RXN4hoZkhUkkrnef9nTUDw3E3vVALAD8Kx
|
||||
{"blackjok3r2", "02f7597468703c1c5c8465dd6d43acaae697df9df30bed21494d193412a1ea193e" }, // RWHGbrLSP89fTzNVF9U9xiekDYJqcibTca
|
||||
{"blackjok3r3", "03c3e4c0206551dbf3a4b24d18e5d2737080541184211e3bfd2b1092177410b9c2" }, // RMMav2AVse5XHPvDfTzRpMbFhK3GqFmtSN
|
||||
{"kmdkrazy", "02f7597468703c1c5c8465dd6d43acaae697df9df30bed21494d193412a1ea193e" }, // RWHGbrLSP89fTzNVF9U9xiekDYJqcibTca
|
||||
{"alrighttest", "02e9dfe248f453b499315a90375e58a1c9ad79f5f3932ecb2205399a0f262d65fc" }, // RBevSstS8JtDXMEFNcJws4QTYN4PcE2VL5
|
||||
{"alrighttest1", "03527c7ecd6a8c5db6d685a64e6e18c1edb49e2f057a434f56c3f1253a26e9c6a2" }, // RBw2jNU3dnGk86ZLqPMadJwRwg3NU8eC6s
|
||||
},
|
||||
{
|
||||
{"blackjok3r", "021914947402d936a89fbdd1b12be49eb894a1568e5e17bb18c8a6cffbd3dc106e" }, // RTVti13NP4eeeZaCCmQxc2bnPdHxCJFP9x
|
||||
|
||||
@@ -344,6 +344,9 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param
|
||||
{
|
||||
if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH)
|
||||
return true;
|
||||
|
||||
if ( ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0 && pblock->GetHash().ToString() == "027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71" )
|
||||
return true;
|
||||
|
||||
unsigned int n = params.EquihashN();
|
||||
unsigned int k = params.EquihashK();
|
||||
|
||||
@@ -47,10 +47,8 @@ using namespace std;
|
||||
|
||||
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
|
||||
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
|
||||
int32_t komodo_longestchain();
|
||||
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
|
||||
extern int8_t komodo_segid(int32_t nocache,int32_t height);
|
||||
extern int32_t KOMODO_LONGESTCHAIN;
|
||||
#include "komodo_defs.h"
|
||||
#include "komodo_structs.h"
|
||||
|
||||
double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty)
|
||||
{
|
||||
@@ -628,8 +626,6 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
|
||||
return pblockindex->GetBlockHash().GetHex();
|
||||
}
|
||||
|
||||
extern int32_t ASSETCHAINS_STAKED;
|
||||
|
||||
UniValue getlastsegidstakes(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
@@ -915,20 +911,6 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "komodo_defs.h"
|
||||
#include "komodo_structs.h"
|
||||
|
||||
#define IGUANA_MAXSCRIPTSIZE 10001
|
||||
#define KOMODO_KVDURATION 1440
|
||||
#define KOMODO_KVBINARY 2
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern int32_t ASSETCHAINS_LWMAPOS;
|
||||
uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume);
|
||||
int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel);
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
|
||||
int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width);
|
||||
int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen);
|
||||
|
||||
UniValue kvsearch(const UniValue& params, bool fHelp)
|
||||
{
|
||||
@@ -1174,16 +1156,7 @@ UniValue paxprice(const UniValue& params, bool fHelp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t komodo_heightpricebits(uint64_t *seedp,uint32_t *heightbits,int32_t nHeight);
|
||||
char *komodo_pricename(char *name,int32_t ind);
|
||||
int64_t komodo_priceave(int64_t *tmpbuf,int64_t *correlated,int32_t cskip);
|
||||
int64_t komodo_pricecorrelated(uint64_t seed,int32_t ind,uint32_t *rawprices,int32_t rawskip,uint32_t *nonzprices,int32_t smoothwidth);
|
||||
int32_t komodo_nextheight();
|
||||
uint32_t komodo_heightstamp(int32_t height);
|
||||
int64_t komodo_pricemult(int32_t ind);
|
||||
#define PRICES_SMOOTHWIDTH 1
|
||||
|
||||
int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,int32_t ind)
|
||||
/*int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,int32_t ind)
|
||||
{
|
||||
int32_t height,i,n,width,numpricefeeds = -1; uint64_t seed,ignore,rngval; uint32_t rawprices[1440*6],*ptr; int64_t *tmpbuf;
|
||||
width = numblocks+PRICES_DAYWINDOW*2+PRICES_SMOOTHWIDTH;
|
||||
@@ -1215,14 +1188,14 @@ int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,
|
||||
pricedata[i*3+2] = komodo_priceave(tmpbuf,&pricedata[i*3+1],3);
|
||||
free(tmpbuf);
|
||||
return(0);
|
||||
}
|
||||
}*/
|
||||
|
||||
UniValue prices(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if ( fHelp || params.size() != 1 )
|
||||
throw runtime_error("prices maxsamples\n");
|
||||
LOCK(cs_main);
|
||||
UniValue ret(UniValue::VOBJ); uint64_t seed,rngval; int64_t *tmpbuf,smoothed,*correlated; char name[64],*str; uint32_t rawprices[1440*6],*prices; uint32_t i,width,j,numpricefeeds=-1,n,numsamples,nextheight,offset,ht;
|
||||
UniValue ret(UniValue::VOBJ); uint64_t seed,rngval; int64_t *tmpbuf,smoothed,*correlated,checkprices[PRICES_MAXDATAPOINTS]; char name[64],*str; uint32_t rawprices[1440*6],*prices; uint32_t i,width,j,numpricefeeds=-1,n,numsamples,nextheight,offset,ht;
|
||||
if ( ASSETCHAINS_CBOPRET == 0 )
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "only -ac_cbopret chains have prices");
|
||||
|
||||
@@ -1282,12 +1255,30 @@ UniValue prices(const UniValue& params, bool fHelp)
|
||||
rngval = (rngval*11109 + 13849);
|
||||
if ( (correlated[i]= komodo_pricecorrelated(rngval,j,&prices[offset],1,0,PRICES_SMOOTHWIDTH)) < 0 )
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "null correlated price");
|
||||
{
|
||||
if ( komodo_priceget(checkprices,j,nextheight-1-i,1) >= 0 )
|
||||
{
|
||||
if ( checkprices[1] != correlated[i] )
|
||||
{
|
||||
//fprintf(stderr,"ind.%d ht.%d %.8f != %.8f\n",j,nextheight-1-i,(double)checkprices[1]/COIN,(double)correlated[i]/COIN);
|
||||
correlated[i] = checkprices[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tmpbuf = (int64_t *)calloc(sizeof(int64_t),2*PRICES_DAYWINDOW);
|
||||
for (i=0; i<maxsamples&&i<numsamples; i++)
|
||||
{
|
||||
offset = j*width + i;
|
||||
smoothed = komodo_priceave(tmpbuf,&correlated[i],1);
|
||||
if ( komodo_priceget(checkprices,j,nextheight-1-i,1) >= 0 )
|
||||
{
|
||||
if ( checkprices[2] != smoothed )
|
||||
{
|
||||
fprintf(stderr,"ind.%d ht.%d %.8f != %.8f\n",j,nextheight-1-i,(double)checkprices[2]/COIN,(double)smoothed/COIN);
|
||||
smoothed = checkprices[2];
|
||||
}
|
||||
}
|
||||
UniValue parr(UniValue::VARR);
|
||||
parr.push_back(ValueFromAmount((int64_t)prices[offset] * komodo_pricemult(j)));
|
||||
parr.push_back(ValueFromAmount(correlated[i]));
|
||||
@@ -1324,8 +1315,6 @@ UniValue prices(const UniValue& params, bool fHelp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight);
|
||||
|
||||
UniValue gettxout(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 2 || params.size() > 3)
|
||||
|
||||
@@ -108,6 +108,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "lockunspent", 0 },
|
||||
{ "lockunspent", 1 },
|
||||
{ "importprivkey", 2 },
|
||||
{ "importprivkey", 3 },
|
||||
{ "importaddress", 2 },
|
||||
{ "verifychain", 0 },
|
||||
{ "verifychain", 1 },
|
||||
@@ -174,6 +175,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "getNotarisationsForBlock", 0},
|
||||
{ "height_MoM", 1},
|
||||
{ "calc_MoM", 2},
|
||||
{ "migrate_completeimporttransaction", 1},
|
||||
};
|
||||
|
||||
class CRPCConvertTable
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include "key_io.h"
|
||||
#include "cc/CCImportGateway.h"
|
||||
#include "cc/CCtokens.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <univalue.h>
|
||||
@@ -52,6 +53,8 @@ extern std::string CCerror;
|
||||
extern std::string ASSETCHAINS_SELFIMPORT;
|
||||
extern uint16_t ASSETCHAINS_CODAPORT, ASSETCHAINS_BEAMPORT;
|
||||
int32_t ensure_CCrequirements(uint8_t evalcode);
|
||||
bool EnsureWalletIsAvailable(bool avoidException);
|
||||
|
||||
|
||||
int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip);
|
||||
int32_t komodo_MoMoMdata(char *hexstr,int32_t hexsize,struct komodo_ccdataMoMoM *mdata,char *symbol,int32_t kmdheight,int32_t notarized_height);
|
||||
@@ -60,8 +63,8 @@ uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
|
||||
int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
|
||||
extern std::string ASSETCHAINS_SELFIMPORT;
|
||||
|
||||
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx);
|
||||
int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount);
|
||||
//std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx);
|
||||
//int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount);
|
||||
std::string MakeCodaImportTx(uint64_t txfee, std::string receipt, std::string srcaddr, std::vector<CTxOut> vouts);
|
||||
|
||||
UniValue assetchainproof(const UniValue& params, bool fHelp)
|
||||
@@ -137,12 +140,12 @@ UniValue MoMoMdata(const UniValue& params, bool fHelp)
|
||||
int kmdheight = atoi(params[1].get_str().c_str());
|
||||
uint32_t ccid = atoi(params[2].get_str().c_str());
|
||||
ret.push_back(Pair("coin",symbol));
|
||||
ret.push_back(Pair("kmdheight",kmdheight));
|
||||
ret.push_back(Pair("kmdheight",kmdheight-5));
|
||||
ret.push_back(Pair("ccid", (int) ccid));
|
||||
|
||||
uint256 destNotarisationTxid;
|
||||
std::vector<uint256> moms;
|
||||
uint256 MoMoM = CalculateProofRoot(symbol, ccid, kmdheight, moms, destNotarisationTxid);
|
||||
uint256 MoMoM = CalculateProofRoot(symbol, ccid, kmdheight-5, moms, destNotarisationTxid);
|
||||
|
||||
UniValue valMoms(UniValue::VARR);
|
||||
for (int i=0; i<moms.size(); i++) valMoms.push_back(moms[i].GetHex());
|
||||
@@ -185,7 +188,7 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp)
|
||||
"If neccesary, the transaction should be funded using fundrawtransaction.\n"
|
||||
"Finally, the transaction should be signed using signrawtransaction\n"
|
||||
"The finished export transaction, plus the payouts, should be passed to "
|
||||
"the \"migrate_createimporttransaction\" method on a KMD node to get the corresponding "
|
||||
"the \"migrate_createimporttransaction\" method to get the corresponding "
|
||||
"import transaction.\n"
|
||||
);
|
||||
|
||||
@@ -206,19 +209,30 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp)
|
||||
|
||||
if (strcmp(ASSETCHAINS_SYMBOL,targetSymbol.c_str()) == 0)
|
||||
throw runtime_error("cant send a coin to the same chain");
|
||||
|
||||
/// Tested 44 vins p2pkh inputs as working. Set this at 25, but its a tx size limit.
|
||||
// likely with a single RPC you can limit it by the size of tx.
|
||||
if (tx.vout.size() > 25)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Cannot have more than 50 vins, transaction too large.");
|
||||
|
||||
CAmount burnAmount = 0;
|
||||
|
||||
for (int i=0; i<tx.vout.size(); i++) burnAmount += tx.vout[i].nValue;
|
||||
if (burnAmount <= 0)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export a negative or zero value.");
|
||||
// This is due to MAX MONEY in target. We set it at min 1 million coins, so you cant export more than 1 million,
|
||||
// without knowing the MAX money on the target this was the easiest solution.
|
||||
if (burnAmount > 1000000LL*COIN)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export more than 1 million coins per export.");
|
||||
|
||||
/* note: we marshal to rawproof in a different way (to be able to add other objects)
|
||||
rawproof.resize(strlen(ASSETCHAINS_SYMBOL));
|
||||
ptr = rawproof.data();
|
||||
for (i=0; i<rawproof.size(); i++)
|
||||
ptr[i] = ASSETCHAINS_SYMBOL[i];
|
||||
ptr[i] = ASSETCHAINS_SYMBOL[i]; */
|
||||
const std::string chainSymbol(ASSETCHAINS_SYMBOL);
|
||||
rawproof = E_MARSHAL(ss << chainSymbol); // add src chain name
|
||||
|
||||
CTxOut burnOut = MakeBurnOutput(burnAmount+txfee, ccid, targetSymbol, tx.vout,rawproof);
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("payouts", HexStr(E_MARSHAL(ss << tx.vout))));
|
||||
@@ -228,26 +242,308 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// creates burn tx as an alternative to 'migrate_converttoexport()'
|
||||
UniValue migrate_createburntransaction(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
//uint8_t *ptr;
|
||||
//uint8_t i;
|
||||
uint32_t ccid = ASSETCHAINS_CC;
|
||||
int64_t txfee = 10000;
|
||||
|
||||
if (fHelp || params.size() != 3 && params.size() != 4)
|
||||
throw runtime_error(
|
||||
"migrate_createburntransaction dest_symbol dest_addr amount [tokenid]\n"
|
||||
"\nCreates a raw burn transaction to make a cross-chain coin or non-fungible token transfer.\n"
|
||||
"The parameters:\n"
|
||||
"dest_symbol destination chain ac_name\n"
|
||||
"dest_addr address on the destination chain where coins are to be sent or pubkey if tokens are to be sent\n"
|
||||
"amount amount in coins to be burned on the source chain and sent to the destination address/pubkey on the destination chain, for tokens should be equal to 1\n"
|
||||
"tokenid token id, if tokens are transferred (optional). Only non-fungible tokens are supported\n"
|
||||
"\n"
|
||||
"The transaction should be sent using sendrawtransaction to the source chain\n"
|
||||
"The finished burn transaction and payouts should be also passed to "
|
||||
"the \"migrate_createimporttransaction\" method to get the corresponding import transaction.\n"
|
||||
);
|
||||
|
||||
if (ASSETCHAINS_CC < KOMODO_FIRSTFUNGIBLEID)
|
||||
throw runtime_error("-ac_cc < KOMODO_FIRSTFUNGIBLEID");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] == 0)
|
||||
throw runtime_error("Must be called on assetchain");
|
||||
|
||||
// if -pubkey not set it sends change to null pubkey.
|
||||
// we need a better way to return errors from this function!
|
||||
if (ensure_CCrequirements(225) < 0)
|
||||
throw runtime_error("You need to set -pubkey, or run setpukbey RPC, or imports are disabled on this chain.");
|
||||
|
||||
string targetSymbol = params[0].get_str();
|
||||
if (targetSymbol.size() == 0 || targetSymbol.size() > 32)
|
||||
throw runtime_error("targetSymbol length must be >0 and <=32");
|
||||
|
||||
if (strcmp(ASSETCHAINS_SYMBOL, targetSymbol.c_str()) == 0)
|
||||
throw runtime_error("cant send a coin to the same chain");
|
||||
|
||||
std::string dest_addr_or_pubkey = params[1].get_str();
|
||||
|
||||
CAmount burnAmount;
|
||||
if(params.size() == 3)
|
||||
burnAmount = (CAmount)( atof(params[2].get_str().c_str()) * COIN + 0.00000000499999 );
|
||||
else
|
||||
burnAmount = atoll(params[2].get_str().c_str());
|
||||
|
||||
if (burnAmount <= 0)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export a negative or zero value.");
|
||||
if (burnAmount > 1000000LL * COIN)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export more than 1 million coins per export.");
|
||||
|
||||
uint256 tokenid = zeroid;
|
||||
if( params.size() == 4 )
|
||||
tokenid = Parseuint256(params[3].get_str().c_str());
|
||||
|
||||
CPubKey myPubKey = Mypubkey();
|
||||
struct CCcontract_info *cpTokens, C;
|
||||
cpTokens = CCinit(&C, EVAL_TOKENS);
|
||||
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
|
||||
const std::string chainSymbol(ASSETCHAINS_SYMBOL);
|
||||
std::vector<uint8_t> rawproof; //(chainSymbol.begin(), chainSymbol.end());
|
||||
|
||||
if (tokenid.IsNull()) { // coins
|
||||
int64_t inputs;
|
||||
if ((inputs = AddNormalinputs(mtx, myPubKey, burnAmount + txfee, 60)) == 0) {
|
||||
throw runtime_error("Cannot find normal inputs\n");
|
||||
}
|
||||
|
||||
CTxDestination txdest = DecodeDestination(dest_addr_or_pubkey.c_str());
|
||||
CScript scriptPubKey = GetScriptForDestination(txdest);
|
||||
if (!scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Incorrect destination addr.");
|
||||
}
|
||||
mtx.vout.push_back(CTxOut(burnAmount, scriptPubKey)); // 'model' vout
|
||||
ret.push_back(Pair("payouts", HexStr(E_MARSHAL(ss << mtx.vout)))); // save 'model' vout
|
||||
|
||||
rawproof = E_MARSHAL(ss << chainSymbol); // add src chain name
|
||||
|
||||
CTxOut burnOut = MakeBurnOutput(burnAmount+txfee, ccid, targetSymbol, mtx.vout, rawproof); //make opret with burned amount
|
||||
|
||||
mtx.vout.clear(); // remove 'model' vout
|
||||
|
||||
int64_t change = inputs - (burnAmount+txfee);
|
||||
if (change != 0)
|
||||
mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG)); // make change here to prevent it from making in FinalizeCCtx
|
||||
|
||||
mtx.vout.push_back(burnOut); // mtx now has only burned vout (that is, amount sent to OP_RETURN making it unspendable)
|
||||
//std::string exportTxHex = FinalizeCCTx(0, cpTokens, mtx, myPubKey, txfee, CScript()); // no change no opret
|
||||
|
||||
}
|
||||
else { // tokens
|
||||
CTransaction tokenbasetx;
|
||||
uint256 hashBlock;
|
||||
vscript_t vopretNonfungible;
|
||||
vscript_t vopretBurnData;
|
||||
std::vector<uint8_t> vorigpubkey, vdestpubkey;
|
||||
std::string name, description;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if (!myGetTransaction(tokenid, tokenbasetx, hashBlock))
|
||||
throw runtime_error("Could not load token creation tx\n");
|
||||
|
||||
// check if it is non-fungible tx and get its second evalcode from non-fungible payload
|
||||
if (tokenbasetx.vout.size() == 0)
|
||||
throw runtime_error("No vouts in token tx\n");
|
||||
|
||||
if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, description, oprets) != 'c')
|
||||
throw runtime_error("Incorrect token creation tx\n");
|
||||
GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible);
|
||||
/* allow fungible tokens:
|
||||
if (vopretNonfungible.empty())
|
||||
throw runtime_error("No non-fungible token data\n"); */
|
||||
|
||||
uint8_t destEvalCode = EVAL_TOKENS;
|
||||
if (!vopretNonfungible.empty())
|
||||
destEvalCode = vopretNonfungible.begin()[0];
|
||||
|
||||
// check non-fungible tokens amount
|
||||
if (!vopretNonfungible.empty() && burnAmount != 1)
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "For non-fungible tokens amount should be equal to 1.");
|
||||
|
||||
vdestpubkey = ParseHex(dest_addr_or_pubkey);
|
||||
CPubKey destPubKey = pubkey2pk(vdestpubkey);
|
||||
if (!destPubKey.IsValid())
|
||||
throw runtime_error("Invalid destination pubkey\n");
|
||||
|
||||
int64_t inputs;
|
||||
if ((inputs = AddNormalinputs(mtx, myPubKey, txfee, 1)) == 0) // for miners in dest chain
|
||||
throw runtime_error("No normal input found for two txfee\n");
|
||||
|
||||
int64_t ccInputs;
|
||||
if ((ccInputs = AddTokenCCInputs(cpTokens, mtx, myPubKey, tokenid, burnAmount, 4)) < burnAmount)
|
||||
throw runtime_error("No token inputs found (please try to consolidate tokens)\n");
|
||||
|
||||
// make payouts (which will be in the import tx with token):
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens, NULL))); // new marker to token cc addr, burnable and validated, vout position now changed to 0 (from 1)
|
||||
mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, burnAmount, destPubKey));
|
||||
|
||||
std::vector<std::pair<uint8_t, vscript_t>> voprets;
|
||||
if (!vopretNonfungible.empty())
|
||||
voprets.push_back(std::make_pair(OPRETID_NONFUNGIBLEDATA, vopretNonfungible)); // add additional opret with non-fungible data
|
||||
|
||||
mtx.vout.push_back(CTxOut((CAmount)0, EncodeTokenCreateOpRet('c', vorigpubkey, name, description, voprets))); // make token import opret
|
||||
ret.push_back(Pair("payouts", HexStr(E_MARSHAL(ss << mtx.vout)))); // save payouts for import tx
|
||||
|
||||
rawproof = E_MARSHAL(ss << chainSymbol << tokenbasetx); // add src chain name and token creation tx
|
||||
|
||||
CTxOut burnOut = MakeBurnOutput(0, ccid, targetSymbol, mtx.vout, rawproof); //make opret with amount=0 because tokens are burned, not coins (see next vout)
|
||||
mtx.vout.clear(); // remove payouts
|
||||
|
||||
// now make burn transaction:
|
||||
mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, burnAmount, pubkey2pk(ParseHex(CC_BURNPUBKEY)))); // burn tokens
|
||||
|
||||
int64_t change = inputs - txfee;
|
||||
if (change != 0)
|
||||
mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG)); // make change here to prevent it from making in FinalizeCCtx
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(pubkey2pk(ParseHex(CC_BURNPUBKEY))); // maybe we do not need this because ccTokens has the const for burn pubkey
|
||||
|
||||
int64_t ccChange = ccInputs - burnAmount;
|
||||
if (ccChange != 0)
|
||||
mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, ccChange, myPubKey));
|
||||
|
||||
GetOpReturnData(burnOut.scriptPubKey, vopretBurnData);
|
||||
mtx.vout.push_back(CTxOut(txfee, EncodeTokenOpRet(tokenid, voutTokenPubkeys, std::make_pair(OPRETID_BURNDATA, vopretBurnData)))); //burn txfee for miners in dest chain
|
||||
}
|
||||
|
||||
std::string burnTxHex = FinalizeCCTx(0, cpTokens, mtx, myPubKey, txfee, CScript()); //no change, no opret
|
||||
ret.push_back(Pair("BurnTxHex", burnTxHex));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// util func to check burn tx and source chain params
|
||||
void CheckBurnTxSource(uint256 burntxid, UniValue &info) {
|
||||
|
||||
CTransaction burnTx;
|
||||
uint256 blockHash;
|
||||
|
||||
if (!GetTransaction(burntxid, burnTx, blockHash, true))
|
||||
throw std::runtime_error("Cannot find burn transaction");
|
||||
|
||||
if (blockHash.IsNull())
|
||||
throw std::runtime_error("Burn tx still in mempool");
|
||||
|
||||
uint256 payoutsHash;
|
||||
std::string targetSymbol;
|
||||
uint32_t targetCCid;
|
||||
std::vector<uint8_t> rawproof;
|
||||
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof))
|
||||
throw std::runtime_error("Cannot unmarshal burn tx data");
|
||||
|
||||
vscript_t vopret;
|
||||
std::string sourceSymbol;
|
||||
CTransaction tokenbasetxStored;
|
||||
uint256 tokenid = zeroid;
|
||||
|
||||
if (burnTx.vout.size() > 0 && GetOpReturnData(burnTx.vout.back().scriptPubKey, vopret) && !vopret.empty()) {
|
||||
if (vopret.begin()[0] == EVAL_TOKENS) {
|
||||
if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol; ss >> tokenbasetxStored))
|
||||
throw std::runtime_error("Cannot unmarshal rawproof for tokens");
|
||||
|
||||
uint8_t evalCode;
|
||||
std::vector<CPubKey> voutPubkeys;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
if( DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCode, tokenid, voutPubkeys, oprets) == 0 )
|
||||
throw std::runtime_error("Cannot decode token opret in burn tx");
|
||||
|
||||
if( tokenid != tokenbasetxStored.GetHash() )
|
||||
throw std::runtime_error("Incorrect tokenbase in burn tx");
|
||||
|
||||
CTransaction tokenbasetx;
|
||||
uint256 hashBlock;
|
||||
if (!myGetTransaction(tokenid, tokenbasetx, hashBlock)) {
|
||||
throw std::runtime_error("Could not load tokenbase tx");
|
||||
}
|
||||
|
||||
// check if nonfungible data present
|
||||
if (tokenbasetx.vout.size() > 0) {
|
||||
std::vector<uint8_t> origpubkey;
|
||||
std::string name, description;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
vscript_t vopretNonfungible;
|
||||
if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, origpubkey, name, description, oprets) == 'c') {
|
||||
GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible);
|
||||
if (vopretNonfungible.empty())
|
||||
throw std::runtime_error("Could not migrate fungible tokens");
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Could not decode opreturn in tokenbase tx");
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Incorrect tokenbase tx: not opreturn");
|
||||
|
||||
|
||||
struct CCcontract_info *cpTokens, CCtokens_info;
|
||||
cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS);
|
||||
int64_t ccInputs = 0, ccOutputs = 0;
|
||||
if( !TokensExactAmounts(true, cpTokens, ccInputs, ccOutputs, NULL, burnTx, tokenid) )
|
||||
throw std::runtime_error("Incorrect token burn tx: cc inputs <> cc outputs");
|
||||
}
|
||||
else if (vopret.begin()[0] == EVAL_IMPORTCOIN) {
|
||||
if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol))
|
||||
throw std::runtime_error("Cannot unmarshal rawproof for coins");
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Incorrect eval code in opreturn");
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("No opreturn in burn tx");
|
||||
|
||||
|
||||
if (sourceSymbol != ASSETCHAINS_SYMBOL)
|
||||
throw std::runtime_error("Incorrect source chain in rawproof");
|
||||
|
||||
if (targetCCid != ASSETCHAINS_CC)
|
||||
throw std::runtime_error("Incorrect CCid in burn tx");
|
||||
|
||||
if (targetSymbol == ASSETCHAINS_SYMBOL)
|
||||
throw std::runtime_error("Must not be called on the destination chain");
|
||||
|
||||
// fill info to return for the notary operator (if manual notarization) or user
|
||||
info.push_back(Pair("SourceSymbol", sourceSymbol));
|
||||
info.push_back(Pair("TargetSymbol", targetSymbol));
|
||||
info.push_back(Pair("TargetCCid", std::to_string(targetCCid)));
|
||||
if (!tokenid.IsNull())
|
||||
info.push_back(Pair("tokenid", tokenid.GetHex()));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The process to migrate funds
|
||||
* The process to migrate funds from a chain to chain
|
||||
*
|
||||
* Create a transaction on assetchain:
|
||||
* 1.Create a transaction on assetchain (deprecated):
|
||||
* 1.1 generaterawtransaction
|
||||
* 1.2 migrate_converttoexport
|
||||
* 1.3 fundrawtransaction
|
||||
* 1.4 signrawtransaction
|
||||
*
|
||||
* generaterawtransaction
|
||||
* migrate_converttoexport
|
||||
* fundrawtransaction
|
||||
* signrawtransaction
|
||||
* alternatively, burn (export) transaction may be created with this new rpc call:
|
||||
* 1. migrate_createburntransaction
|
||||
*
|
||||
* migrate_createimportransaction
|
||||
* migrate_completeimporttransaction
|
||||
* next steps:
|
||||
* 2. migrate_createimporttransaction
|
||||
* 3. migrate_completeimporttransaction
|
||||
*/
|
||||
|
||||
UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 2)
|
||||
throw runtime_error("migrate_createimporttransaction burnTx payouts\n\n"
|
||||
"Create an importTx given a burnTx and the corresponding payouts, hex encoded");
|
||||
if (fHelp || params.size() < 2)
|
||||
throw runtime_error("migrate_createimporttransaction burnTx payouts [notarytxid-1]..[notarytxid-N]\n\n"
|
||||
"Create an importTx given a burnTx and the corresponding payouts, hex encoded\n"
|
||||
"optional notarytxids are txids of notary operator proofs of burn tx existense (from destination chain).\n"
|
||||
"Do not make subsequent call to migrate_completeimporttransaction if notary txids are set");
|
||||
|
||||
if (ASSETCHAINS_CC < KOMODO_FIRSTFUNGIBLEID)
|
||||
throw runtime_error("-ac_cc < KOMODO_FIRSTFUNGIBLEID");
|
||||
@@ -261,26 +557,52 @@ UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp)
|
||||
if (!E_UNMARSHAL(txData, ss >> burnTx))
|
||||
throw runtime_error("Couldn't parse burnTx");
|
||||
|
||||
if( burnTx.vin.size() == 0 )
|
||||
throw runtime_error("No vins in the burnTx");
|
||||
|
||||
if (burnTx.vout.size() == 0)
|
||||
throw runtime_error("No vouts in the burnTx");
|
||||
|
||||
|
||||
vector<CTxOut> payouts;
|
||||
if (!E_UNMARSHAL(ParseHexV(params[1], "argument 2"), ss >> payouts))
|
||||
throw runtime_error("Couldn't parse payouts");
|
||||
|
||||
uint256 txid = burnTx.GetHash();
|
||||
TxProof proof = GetAssetchainProof(burnTx.GetHash(),burnTx);
|
||||
ImportProof importProof;
|
||||
if (params.size() == 2) { // standard MoMoM based notarization
|
||||
// get MoM import proof
|
||||
importProof = ImportProof(GetAssetchainProof(burnTx.GetHash(), burnTx));
|
||||
}
|
||||
else { // notarization by manual operators notary tx
|
||||
UniValue info(UniValue::VOBJ);
|
||||
CheckBurnTxSource(burnTx.GetHash(), info);
|
||||
|
||||
CTransaction importTx = MakeImportCoinTransaction(proof, burnTx, payouts);
|
||||
// get notary import proof
|
||||
std::vector<uint256> notaryTxids;
|
||||
for (int i = 2; i < params.size(); i++) {
|
||||
uint256 txid = Parseuint256(params[i].get_str().c_str());
|
||||
if (txid.IsNull())
|
||||
throw runtime_error("Incorrect notary approval txid");
|
||||
notaryTxids.push_back(txid);
|
||||
}
|
||||
importProof = ImportProof(notaryTxids);
|
||||
}
|
||||
|
||||
return HexStr(E_MARSHAL(ss << importTx));
|
||||
CTransaction importTx = MakeImportCoinTransaction(importProof, burnTx, payouts);
|
||||
|
||||
std::string importTxHex = HexStr(E_MARSHAL(ss << importTx));
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("ImportTxHex", importTxHex));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error("migrate_completeimporttransaction importTx\n\n"
|
||||
if (fHelp || params.size() < 1 || params.size() > 2)
|
||||
throw runtime_error("migrate_completeimporttransaction importTx [offset]\n\n"
|
||||
"Takes a cross chain import tx with proof generated on assetchain "
|
||||
"and extends proof to target chain proof root");
|
||||
"and extends proof to target chain proof root\n"
|
||||
"offset is optional, use it to increase the used KMD height, use when import fails.");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] != 0)
|
||||
throw runtime_error("Must be called on KMD");
|
||||
@@ -288,63 +610,130 @@ UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp)
|
||||
CTransaction importTx;
|
||||
if (!E_UNMARSHAL(ParseHexV(params[0], "argument 1"), ss >> importTx))
|
||||
throw runtime_error("Couldn't parse importTx");
|
||||
|
||||
int32_t offset = 0;
|
||||
if ( params.size() == 2 )
|
||||
offset = params[1].get_int();
|
||||
|
||||
CompleteImportTransaction(importTx);
|
||||
CompleteImportTransaction(importTx, offset);
|
||||
|
||||
return HexStr(E_MARSHAL(ss << importTx));
|
||||
std::string importTxHex = HexStr(E_MARSHAL(ss << importTx));
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("ImportTxHex", importTxHex));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Alternate coin migration solution if MoMoM migration has failed
|
||||
*
|
||||
* The workflow:
|
||||
* On the source chain user calls migrate_createburntransaction, sends the burn tx to the chain and sends its txid and the source chain name to the notary operators (off-chain)
|
||||
* the notary operators call migrate_checkburntransactionsource on the source chain
|
||||
* on the destination chain the notary operators call migrate_createnotaryapprovaltransaction and pass the burn txid and txoutproof received from the previous call,
|
||||
* the notary operators send the approval transactions to the chain and send their txids to the user (off-chain)
|
||||
* on the source chain the user calls migrate_createimporttransaction and passes to it notary txids as additional parameters
|
||||
* then the user sends the import transaction to the destination chain (where the notary approvals will be validated)
|
||||
*/
|
||||
|
||||
// checks if burn tx exists and params stored in the burn tx match to the source chain
|
||||
// returns txproof
|
||||
// run it on the source chain
|
||||
UniValue migrate_checkburntransactionsource(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error("migrate_checkburntransactionsource burntxid\n\n"
|
||||
"checks if params stored in the burn tx match to its tx chain");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] == 0)
|
||||
throw runtime_error("Must be called on asset chain");
|
||||
|
||||
uint256 burntxid = Parseuint256(params[0].get_str().c_str());
|
||||
UniValue result(UniValue::VOBJ);
|
||||
CheckBurnTxSource(burntxid, result); // check and get burn tx data
|
||||
|
||||
// get tx proof for burn tx
|
||||
UniValue nextparams(UniValue::VARR);
|
||||
UniValue txids(UniValue::VARR);
|
||||
txids.push_back(burntxid.GetHex());
|
||||
nextparams.push_back(txids);
|
||||
result.push_back(Pair("TxOutProof", gettxoutproof(nextparams, false))); // get txoutproof
|
||||
result.push_back(Pair("result", "success")); // get txoutproof
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// creates a tx for the dest chain with txproof
|
||||
// used as a momom-backup manual import solution
|
||||
// run it on the dest chain
|
||||
UniValue migrate_createnotaryapprovaltransaction(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 2)
|
||||
throw runtime_error("migrate_createnotaryapprovaltransaction burntxid txoutproof\n\n"
|
||||
"Creates a tx for destination chain with burn tx proof\n"
|
||||
"txoutproof should be retrieved by komodo-cli migrate_checkburntransactionsource call on the source chain\n" );
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] == 0)
|
||||
throw runtime_error("Must be called on asset chain");
|
||||
|
||||
uint256 burntxid = Parseuint256(params[0].get_str().c_str());
|
||||
if (burntxid.IsNull())
|
||||
throw runtime_error("Couldn't parse burntxid or it is null");
|
||||
|
||||
std::vector<uint8_t> proofData = ParseHex(params[1].get_str());
|
||||
CMerkleBlock merkleBlock;
|
||||
std::vector<uint256> prooftxids;
|
||||
if (!E_UNMARSHAL(proofData, ss >> merkleBlock))
|
||||
throw runtime_error("Couldn't parse txoutproof");
|
||||
|
||||
merkleBlock.txn.ExtractMatches(prooftxids);
|
||||
if (std::find(prooftxids.begin(), prooftxids.end(), burntxid) == prooftxids.end())
|
||||
throw runtime_error("No burntxid in txoutproof");
|
||||
|
||||
const int64_t txfee = 10000;
|
||||
struct CCcontract_info *cpDummy, C;
|
||||
cpDummy = CCinit(&C, EVAL_TOKENS); // just for FinalizeCCtx to work
|
||||
|
||||
// creating a tx with proof:
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
if (AddNormalinputs(mtx, Mypubkey(), txfee*2, 4) == 0)
|
||||
throw runtime_error("Cannot find normal inputs\n");
|
||||
|
||||
mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(Mypubkey())) << OP_CHECKSIG));
|
||||
std::string notaryTxHex = FinalizeCCTx(0, cpDummy, mtx, Mypubkey(), txfee, CScript() << OP_RETURN << E_MARSHAL(ss << proofData;));
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("NotaryTxHex", notaryTxHex));
|
||||
return result;
|
||||
}
|
||||
|
||||
// creates a source 'quasi-burn' tx for AC_PUBKEY
|
||||
// run it on the same asset chain
|
||||
UniValue selfimport(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
CMutableTransaction sourceMtx, templateMtx;
|
||||
std::string destaddr;
|
||||
std::string source;
|
||||
std::string rawsourcetx;
|
||||
std::string sourceTxHex;
|
||||
std::string importTxHex;
|
||||
CTransaction burnTx;
|
||||
CTxOut burnOut;
|
||||
uint64_t burnAmount;
|
||||
uint256 sourcetxid, blockHash;
|
||||
std::vector<CTxOut> vouts;
|
||||
std::vector<uint8_t> rawproof, rawproofEmpty;
|
||||
int32_t ivout = 0;
|
||||
CScript scriptPubKey;
|
||||
TxProof proof;
|
||||
std::vector<uint8_t> rawproof;
|
||||
|
||||
if ( ASSETCHAINS_SELFIMPORT.size() == 0 )
|
||||
throw runtime_error("selfimport only works on -ac_import chains");
|
||||
|
||||
if (fHelp || params.size() != 2)
|
||||
throw runtime_error("selfimport destaddr amount\n"
|
||||
//old: "selfimport rawsourcetx sourcetxid {nvout|\"find\"} amount \n"
|
||||
//TODO: "or selfimport rawburntx burntxid {nvout|\"find\"} rawproof source bindtxid height} \n"
|
||||
"\ncreates self import coin transaction");
|
||||
|
||||
/* OLD selfimport schema:
|
||||
rawsourcetx = params[0].get_str();
|
||||
sourcetxid = Parseuint256((char *)params[1].get_str().c_str()); // allow for txid != hash(rawtx)
|
||||
|
||||
int32_t ivout = -1;
|
||||
if( params[2].get_str() != "find" ) {
|
||||
if( !std::all_of(params[2].get_str().begin(), params[2].get_str().end(), ::isdigit) ) // check if not all chars are digit
|
||||
throw std::runtime_error("incorrect nvout param");
|
||||
|
||||
ivout = atoi(params[2].get_str().c_str());
|
||||
}
|
||||
|
||||
burnAmount = atof(params[3].get_str().c_str()) * COIN + 0.00000000499999; */
|
||||
|
||||
destaddr = params[0].get_str();
|
||||
burnAmount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
|
||||
source = ASSETCHAINS_SELFIMPORT; //defaults to -ac_import=... param
|
||||
/* TODO for gateways:
|
||||
if ( params.size() >= 5 )
|
||||
{
|
||||
rawproof = ParseHex(params[4].get_str().c_str());
|
||||
if ( params.size() == 6 )
|
||||
source = params[5].get_str();
|
||||
} */
|
||||
|
||||
if (source == "BEAM")
|
||||
{
|
||||
@@ -364,51 +753,34 @@ UniValue selfimport(const UniValue& params, bool fHelp)
|
||||
}
|
||||
else if (source == "PUBKEY")
|
||||
{
|
||||
|
||||
ImportProof proofNull;
|
||||
CTxDestination dest = DecodeDestination(destaddr.c_str());
|
||||
rawsourcetx = MakeSelfImportSourceTx(dest, burnAmount, sourceMtx);
|
||||
sourcetxid = sourceMtx.GetHash();
|
||||
|
||||
CMutableTransaction sourceMtx = MakeSelfImportSourceTx(dest, burnAmount); // make self-import source tx
|
||||
vscript_t rawProofEmpty;
|
||||
|
||||
CMutableTransaction templateMtx;
|
||||
// prepare self-import 'quasi-burn' tx and also create vout for import tx (in mtx.vout):
|
||||
if (GetSelfimportProof(source, templateMtx, scriptPubKey, proof, rawsourcetx, ivout, sourcetxid, burnAmount) < 0)
|
||||
throw std::runtime_error("Failed validating selfimport");
|
||||
if (GetSelfimportProof(sourceMtx, templateMtx, proofNull) < 0)
|
||||
throw std::runtime_error("Failed creating selfimport template tx");
|
||||
|
||||
vouts = templateMtx.vout;
|
||||
burnOut = MakeBurnOutput(burnAmount, 0xffffffff, ASSETCHAINS_SELFIMPORT, vouts, rawproofEmpty);
|
||||
burnOut = MakeBurnOutput(burnAmount, 0xffffffff, ASSETCHAINS_SELFIMPORT, vouts, rawProofEmpty);
|
||||
templateMtx.vout.clear();
|
||||
templateMtx.vout.push_back(burnOut); // burn tx has only opret with vouts and optional proof
|
||||
|
||||
burnTx = templateMtx; // complete the creation of 'quasi-burn' tx
|
||||
|
||||
std::string hextx = HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proof, burnTx, vouts)));
|
||||
|
||||
CTxDestination address;
|
||||
bool fValidAddress = ExtractDestination(scriptPubKey, address);
|
||||
|
||||
result.push_back(Pair("sourceTxHex", rawsourcetx));
|
||||
result.push_back(Pair("importTxHex", hextx));
|
||||
result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx
|
||||
result.push_back(Pair("DestinationAddress", EncodeDestination(address))); // notify user about the address where the funds will be sent
|
||||
|
||||
sourceTxHex = HexStr(E_MARSHAL(ss << sourceMtx));
|
||||
importTxHex = HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proofNull, burnTx, vouts)));
|
||||
|
||||
result.push_back(Pair("SourceTxHex", sourceTxHex));
|
||||
result.push_back(Pair("ImportTxHex", importTxHex));
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (source == ASSETCHAINS_SELFIMPORT)
|
||||
{
|
||||
throw std::runtime_error("not implemented yet\n");
|
||||
|
||||
if (params.size() != 8)
|
||||
throw runtime_error("use \'selfimport rawburntx burntxid nvout rawproof source bindtxid height\' to import from a coin chain\n");
|
||||
|
||||
uint256 bindtxid = Parseuint256((char *)params[6].get_str().c_str());
|
||||
int32_t height = atoi((char *)params[7].get_str().c_str());
|
||||
|
||||
|
||||
// source is external coin is the assetchains symbol in the burnTx OP_RETURN
|
||||
// burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent
|
||||
//std::string hextx = MakeGatewaysImportTx(0, bindtxid, height, source, rawproof, rawsourcetx, ivout, "");
|
||||
|
||||
// result.push_back(Pair("hex", hextx));
|
||||
// result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -536,13 +908,13 @@ UniValue importgatewaydeposit(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
CMutableTransaction mtx; std::vector<uint8_t> rawproof;
|
||||
std::string hex,coin,rawburntx; int32_t height,burnvout;
|
||||
std::string hex,coin,rawburntx; int32_t height,burnvout; int64_t amount;
|
||||
CPubKey destpub; std::vector<CTxOut> vouts; uint256 bindtxid,burntxid;
|
||||
|
||||
if ( ASSETCHAINS_SELFIMPORT.size() == 0 )
|
||||
throw runtime_error("importgatewaydeposit only works on -ac_import chains");
|
||||
if ( fHelp || params.size() != 8)
|
||||
throw runtime_error("use \'importgatewaydeposit bindtxid height coin burntxid nvout rawburntx rawproof destpub\' to import deposited coins\n");
|
||||
if ( fHelp || params.size() != 9)
|
||||
throw runtime_error("use \'importgatewaydeposit bindtxid height coin burntxid nvout rawburntx rawproof destpub amount\' to import deposited coins\n");
|
||||
if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
CCerror = "";
|
||||
@@ -554,6 +926,7 @@ UniValue importgatewaydeposit(const UniValue& params, bool fHelp)
|
||||
rawburntx = params[5].get_str();
|
||||
rawproof = ParseHex(params[6].get_str());
|
||||
destpub = ParseHex(params[7].get_str());
|
||||
amount = atof(params[8].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if (coin == "BEAM" || coin == "CODA")
|
||||
{
|
||||
ERR_RESULT("for BEAM and CODA import use importdual RPC");
|
||||
@@ -564,7 +937,7 @@ UniValue importgatewaydeposit(const UniValue& params, bool fHelp)
|
||||
ERR_RESULT("source coin not equal to ac_import name");
|
||||
return result;
|
||||
}
|
||||
hex = ImportGatewayDeposit(0, bindtxid, height, coin, burntxid, burnvout, rawburntx, rawproof, destpub);
|
||||
hex = ImportGatewayDeposit(0, bindtxid, height, coin, burntxid, burnvout, rawburntx, rawproof, destpub, amount);
|
||||
RETURN_IF_ERROR(CCerror);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
@@ -626,6 +999,7 @@ UniValue importgatewaypartialsign(const UniValue& params, bool fHelp)
|
||||
coin = params[1].get_str();
|
||||
parthex = params[2].get_str();
|
||||
hex = ImportGatewayPartialSign(0,txid,coin,parthex);
|
||||
RETURN_IF_ERROR(CCerror);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
@@ -933,14 +1307,15 @@ UniValue getimports(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue objTx(UniValue::VOBJ);
|
||||
objTx.push_back(Pair("txid",tx.GetHash().ToString()));
|
||||
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; CTxDestination importaddress;
|
||||
TotalImported += tx.vout[0].nValue;
|
||||
objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[0].nValue)));
|
||||
if (ExtractDestination(tx.vout[0].scriptPubKey, importaddress))
|
||||
ImportProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; CTxDestination importaddress;
|
||||
TotalImported += tx.vout[1].nValue;
|
||||
objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[1].nValue)));
|
||||
if (ExtractDestination(tx.vout[1].scriptPubKey, importaddress))
|
||||
{
|
||||
objTx.push_back(Pair("address", CBitcoinAddress(importaddress).ToString()));
|
||||
}
|
||||
UniValue objBurnTx(UniValue::VOBJ);
|
||||
UniValue objBurnTx(UniValue::VOBJ);
|
||||
CPubKey vinPubkey;
|
||||
if (UnmarshalImportTx(tx, proof, burnTx, payouts))
|
||||
{
|
||||
if (burnTx.vout.size() == 0)
|
||||
@@ -953,8 +1328,14 @@ UniValue getimports(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (rawproof.size() > 0)
|
||||
{
|
||||
std::string sourceSymbol(rawproof.begin(), rawproof.end());
|
||||
std::string sourceSymbol;
|
||||
CTransaction tokenbasetx;
|
||||
E_UNMARSHAL(rawproof, ss >> sourceSymbol;
|
||||
if (!ss.eof())
|
||||
ss >> tokenbasetx );
|
||||
objBurnTx.push_back(Pair("source", sourceSymbol));
|
||||
if( !tokenbasetx.IsNull() )
|
||||
objBurnTx.push_back(Pair("tokenid", tokenbasetx.GetHash().GetHex()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -967,3 +1348,137 @@ UniValue getimports(const UniValue& params, bool fHelp)
|
||||
result.push_back(Pair("time", block.GetBlockTime()));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// outputs burn transactions in the wallet
|
||||
UniValue getwalletburntransactions(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error(
|
||||
"getwalletburntransactions \"count\"\n\n"
|
||||
"Lists most recent wallet burn transactions up to \'count\' parameter\n"
|
||||
"parameter \'count\' is optional. If omitted, defaults to 10 burn transactions"
|
||||
"\n\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" {\n"
|
||||
" \"txid\": (string)\n"
|
||||
" \"burnedAmount\" : (numeric)\n"
|
||||
" \"targetSymbol\" : (string)\n"
|
||||
" \"targetCCid\" : (numeric)\n"
|
||||
" }\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getwalletburntransactions", "100")
|
||||
+ HelpExampleRpc("getwalletburntransactions", "100")
|
||||
+ HelpExampleCli("getwalletburntransactions", "")
|
||||
+ HelpExampleRpc("getwalletburntransactions", "")
|
||||
);
|
||||
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
string strAccount = "*";
|
||||
isminefilter filter = ISMINE_SPENDABLE;
|
||||
int nCount = 10;
|
||||
|
||||
if (params.size() == 1)
|
||||
nCount = atoi(params[0].get_str());
|
||||
if (nCount < 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
|
||||
|
||||
UniValue ret(UniValue::VARR);
|
||||
|
||||
std::list<CAccountingEntry> acentries;
|
||||
CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
|
||||
|
||||
// iterate backwards until we have nCount items to return:
|
||||
for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
|
||||
{
|
||||
CWalletTx *const pwtx = (*it).second.first;
|
||||
if (pwtx != 0)
|
||||
{
|
||||
LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "pwtx iterpos=" << (int32_t)pwtx->nOrderPos << " txid=" << pwtx->GetHash().GetHex() << std::endl);
|
||||
vscript_t vopret;
|
||||
std::string targetSymbol;
|
||||
uint32_t targetCCid; uint256 payoutsHash;
|
||||
std::vector<uint8_t> rawproof;
|
||||
|
||||
if (pwtx->vout.size() > 0 && GetOpReturnData(pwtx->vout.back().scriptPubKey, vopret) && !vopret.empty() &&
|
||||
UnmarshalBurnTx(*pwtx, targetSymbol, &targetCCid, payoutsHash, rawproof)) {
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
entry.push_back(Pair("txid", pwtx->GetHash().GetHex()));
|
||||
if (vopret.begin()[0] == EVAL_TOKENS) {
|
||||
// get burned token value
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
uint256 tokenid;
|
||||
uint8_t evalCodeInOpret;
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
|
||||
//skip token opret:
|
||||
if (DecodeTokenOpRet(pwtx->vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) != 0) {
|
||||
CTransaction tokenbasetx;
|
||||
uint256 hashBlock;
|
||||
|
||||
if (myGetTransaction(tokenid, tokenbasetx, hashBlock)) {
|
||||
std::vector<uint8_t> vorigpubkey;
|
||||
std::string name, description;
|
||||
std::vector<std::pair<uint8_t, vscript_t>> oprets;
|
||||
|
||||
if (tokenbasetx.vout.size() > 0 &&
|
||||
DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, description, oprets) == 'c')
|
||||
{
|
||||
uint8_t destEvalCode = EVAL_TOKENS; // init set to fungible token:
|
||||
vscript_t vopretNonfungible;
|
||||
GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible);
|
||||
if (!vopretNonfungible.empty())
|
||||
destEvalCode = vopretNonfungible.begin()[0];
|
||||
|
||||
int64_t burnAmount = 0;
|
||||
for (auto v : pwtx->vout)
|
||||
if (v.scriptPubKey.IsPayToCryptoCondition() &&
|
||||
CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(destEvalCode ? destEvalCode : EVAL_TOKENS, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey
|
||||
burnAmount += v.nValue;
|
||||
|
||||
entry.push_back(Pair("burnedAmount", ValueFromAmount(burnAmount)));
|
||||
entry.push_back(Pair("tokenid", tokenid.GetHex()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
entry.push_back(Pair("burnedAmount", ValueFromAmount(pwtx->vout.back().nValue))); // coins
|
||||
entry.push_back(Pair("targetSymbol", targetSymbol));
|
||||
entry.push_back(Pair("targetCCid", std::to_string(targetCCid)));
|
||||
if (mytxid_inmempool(pwtx->GetHash()))
|
||||
entry.push_back(Pair("inMempool", "yes"));
|
||||
ret.push_back(entry);
|
||||
}
|
||||
} //else fprintf(stderr,"null pwtx\n
|
||||
if ((int)ret.size() >= (nCount))
|
||||
break;
|
||||
}
|
||||
// ret is newest to oldest
|
||||
|
||||
if (nCount > (int)ret.size())
|
||||
nCount = ret.size();
|
||||
|
||||
vector<UniValue> arrTmp = ret.getValues();
|
||||
|
||||
vector<UniValue>::iterator first = arrTmp.begin();
|
||||
vector<UniValue>::iterator last = arrTmp.begin();
|
||||
std::advance(last, nCount);
|
||||
|
||||
if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
|
||||
if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
|
||||
|
||||
std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
|
||||
|
||||
ret.clear();
|
||||
ret.setArray();
|
||||
ret.push_backV(arrTmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -49,8 +49,10 @@
|
||||
using namespace std;
|
||||
|
||||
#include "komodo_defs.h"
|
||||
extern int32_t ASSETCHAINS_FOUNDERS;
|
||||
|
||||
extern int32_t ASSETCHAINS_FOUNDERS;
|
||||
uint64_t komodo_commission(const CBlock *pblock,int32_t height);
|
||||
int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex);
|
||||
arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc);
|
||||
|
||||
/**
|
||||
@@ -1009,6 +1011,7 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp)
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"miner\" : x.xxx (numeric) The mining reward amount in KMD.\n"
|
||||
" \"ac_pubkey\" : x.xxx (numeric) The mining reward amount in KMD.\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getblocksubsidy", "1000")
|
||||
@@ -1019,11 +1022,32 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp)
|
||||
int nHeight = (params.size()==1) ? params[0].get_int() : chainActive.Height();
|
||||
if (nHeight < 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
|
||||
|
||||
|
||||
CAmount nFoundersReward = 0;
|
||||
CAmount nReward = GetBlockSubsidy(nHeight, Params().GetConsensus());
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("miner", ValueFromAmount(nReward)));
|
||||
//result.push_back(Pair("founders", ValueFromAmount(nFoundersReward)));
|
||||
|
||||
if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 || ASSETCHAINS_SCRIPTPUB.size() > 1 )
|
||||
{
|
||||
if ( ASSETCHAINS_FOUNDERS == 0 && ASSETCHAINS_COMMISSION != 0 )
|
||||
{
|
||||
// ac comission chains need the block to exist to calulate the reward.
|
||||
if ( nHeight <= chainActive.Height() )
|
||||
{
|
||||
CBlockIndex* pblockIndex = chainActive[nHeight];
|
||||
CBlock block;
|
||||
if ( komodo_blockload(block, pblockIndex) == 0 )
|
||||
nFoundersReward = komodo_commission(&block, nHeight);
|
||||
}
|
||||
}
|
||||
else if ( ASSETCHAINS_FOUNDERS != 0 )
|
||||
{
|
||||
// Assetchains founders chains have a fixed reward so can be calculated at any given height.
|
||||
nFoundersReward = komodo_commission(0, nHeight);
|
||||
}
|
||||
result.push_back(Pair("ac_pubkey", ValueFromAmount(nFoundersReward)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -413,7 +413,7 @@ public:
|
||||
|
||||
UniValue coinsupply(const UniValue& params, bool fHelp)
|
||||
{
|
||||
int32_t height = 0; int32_t currentHeight; int64_t sproutfunds,zfunds,supply = 0; UniValue result(UniValue::VOBJ);
|
||||
int32_t height = 0; int32_t currentHeight; int64_t blocks_per_year,zf1,zf3,zf12,sf1,sf3,sf12,sproutfunds,zfunds,supply1,supply3,supply12,supply = 0; UniValue result(UniValue::VOBJ);
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error("coinsupply <height>\n"
|
||||
"\nReturn coin supply information at a given block height. If no height is given, the current height is used.\n"
|
||||
@@ -448,6 +448,27 @@ UniValue coinsupply(const UniValue& params, bool fHelp)
|
||||
result.push_back(Pair("zfunds", ValueFromAmount(zfunds)));
|
||||
result.push_back(Pair("sprout", ValueFromAmount(sproutfunds)));
|
||||
result.push_back(Pair("total", ValueFromAmount(zfunds + supply)));
|
||||
if ( ASSETCHAINS_BLOCKTIME > 0 )
|
||||
{
|
||||
blocks_per_year = 24*3600*365 / ASSETCHAINS_BLOCKTIME;
|
||||
if ( height > blocks_per_year )
|
||||
{
|
||||
supply1 = komodo_coinsupply(&zf1,&sf1,height - blocks_per_year/12);
|
||||
supply3 = komodo_coinsupply(&zf3,&sf3,height - blocks_per_year/4);
|
||||
supply12 = komodo_coinsupply(&zf12,&sf12,height - blocks_per_year);
|
||||
if ( supply1 != 0 && supply3 != 0 && supply12 != 0 )
|
||||
{
|
||||
result.push_back(Pair("lastmonth", ValueFromAmount(supply1+zf1)));
|
||||
result.push_back(Pair("monthcoins", ValueFromAmount(zfunds + supply - supply1-zf1)));
|
||||
result.push_back(Pair("lastquarter", ValueFromAmount(supply3+zf3)));
|
||||
result.push_back(Pair("quartercoins", ValueFromAmount(zfunds + supply - supply3-zf3)));
|
||||
result.push_back(Pair("lastyear", ValueFromAmount(supply12+zf12)));
|
||||
result.push_back(Pair("yearcoins", ValueFromAmount(zfunds + supply - supply12-zf12)));
|
||||
result.push_back(Pair("inflation", 100. * (((double)(zfunds + supply)/(supply12+zf12))-1.)));
|
||||
result.push_back(Pair("blocksperyear", (int64_t)blocks_per_year));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else result.push_back(Pair("error", "couldnt calculate supply"));
|
||||
} else {
|
||||
result.push_back(Pair("error", "invalid height"));
|
||||
@@ -863,11 +884,14 @@ bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &addr
|
||||
|
||||
bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint160, int> > &addresses)
|
||||
{
|
||||
bool ccVout = false;
|
||||
if (params.size() == 2)
|
||||
ccVout = true;
|
||||
if (params[0].isStr()) {
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
uint160 hashBytes;
|
||||
int type = 0;
|
||||
if (!address.GetIndexKey(hashBytes, type, 0)) {
|
||||
if (!address.GetIndexKey(hashBytes, type, ccVout)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
addresses.push_back(std::make_pair(hashBytes, type));
|
||||
@@ -885,7 +909,7 @@ bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint16
|
||||
CBitcoinAddress address(it->get_str());
|
||||
uint160 hashBytes;
|
||||
int type = 0;
|
||||
if (!address.GetIndexKey(hashBytes, type, 0)) {
|
||||
if (!address.GetIndexKey(hashBytes, type, ccVout)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid addresses");
|
||||
}
|
||||
addresses.push_back(std::make_pair(hashBytes, type));
|
||||
@@ -909,7 +933,7 @@ bool timestampSort(std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> a,
|
||||
|
||||
UniValue getaddressmempool(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
if (fHelp || params.size() > 2 || params.size() == 0)
|
||||
throw runtime_error(
|
||||
"getaddressmempool\n"
|
||||
"\nReturns all mempool deltas for an address (requires addressindex to be enabled).\n"
|
||||
@@ -921,6 +945,7 @@ UniValue getaddressmempool(const UniValue& params, bool fHelp)
|
||||
" ,...\n"
|
||||
" ]\n"
|
||||
"}\n"
|
||||
"\nCCvout (optional) Return CCvouts instead of normal vouts\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" {\n"
|
||||
@@ -934,8 +959,8 @@ UniValue getaddressmempool(const UniValue& params, bool fHelp)
|
||||
" }\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressmempool", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'")
|
||||
+ HelpExampleRpc("getaddressmempool", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}")
|
||||
+ HelpExampleCli("getaddressmempool", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}' (ccvout)")
|
||||
+ HelpExampleRpc("getaddressmempool", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]} (ccvout)")
|
||||
);
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
@@ -980,7 +1005,7 @@ UniValue getaddressmempool(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue getaddressutxos(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
if (fHelp || params.size() > 2 || params.size() == 0)
|
||||
throw runtime_error(
|
||||
"getaddressutxos\n"
|
||||
"\nReturns all unspent outputs for an address (requires addressindex to be enabled).\n"
|
||||
@@ -993,6 +1018,7 @@ UniValue getaddressutxos(const UniValue& params, bool fHelp)
|
||||
" ],\n"
|
||||
" \"chainInfo\" (boolean) Include chain info with results\n"
|
||||
"}\n"
|
||||
"\nCCvout (optional) Return CCvouts instead of normal vouts\n"
|
||||
"\nResult\n"
|
||||
"[\n"
|
||||
" {\n"
|
||||
@@ -1005,8 +1031,8 @@ UniValue getaddressutxos(const UniValue& params, bool fHelp)
|
||||
" }\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressutxos", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'")
|
||||
+ HelpExampleRpc("getaddressutxos", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}")
|
||||
+ HelpExampleCli("getaddressutxos", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}' (ccvout)")
|
||||
+ HelpExampleRpc("getaddressutxos", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]} (ccvout)")
|
||||
);
|
||||
|
||||
bool includeChainInfo = false;
|
||||
@@ -1066,7 +1092,7 @@ UniValue getaddressutxos(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue getaddressdeltas(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1 || !params[0].isObject())
|
||||
if (fHelp || params.size() > 2 || params.size() == 0 || !params[0].isObject())
|
||||
throw runtime_error(
|
||||
"getaddressdeltas\n"
|
||||
"\nReturns all changes for an address (requires addressindex to be enabled).\n"
|
||||
@@ -1081,6 +1107,7 @@ UniValue getaddressdeltas(const UniValue& params, bool fHelp)
|
||||
" \"end\" (number) The end block height\n"
|
||||
" \"chainInfo\" (boolean) Include chain info in results, only applies if start and end specified\n"
|
||||
"}\n"
|
||||
"\nCCvout (optional) Return CCvouts instead of normal vouts\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" {\n"
|
||||
@@ -1092,8 +1119,8 @@ UniValue getaddressdeltas(const UniValue& params, bool fHelp)
|
||||
" }\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressdeltas", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'")
|
||||
+ HelpExampleRpc("getaddressdeltas", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}")
|
||||
+ HelpExampleCli("getaddressdeltas", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}' (ccvout)")
|
||||
+ HelpExampleRpc("getaddressdeltas", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]} (ccvout)")
|
||||
);
|
||||
|
||||
|
||||
@@ -1191,7 +1218,7 @@ UniValue getaddressdeltas(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue getaddressbalance(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
if (fHelp ||params.size() > 2 || params.size() == 0)
|
||||
throw runtime_error(
|
||||
"getaddressbalance\n"
|
||||
"\nReturns the balance for an address(es) (requires addressindex to be enabled).\n"
|
||||
@@ -1203,14 +1230,15 @@ UniValue getaddressbalance(const UniValue& params, bool fHelp)
|
||||
" ,...\n"
|
||||
" ]\n"
|
||||
"}\n"
|
||||
"\nCCvout (optional) Return CCvouts instead of normal vouts\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"balance\" (string) The current balance in satoshis\n"
|
||||
" \"received\" (string) The total number of satoshis received (including change)\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'")
|
||||
+ HelpExampleRpc("getaddressbalance", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}")
|
||||
+ HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}' (ccvout)")
|
||||
+ HelpExampleRpc("getaddressbalance", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]} (ccvout)")
|
||||
);
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
@@ -1301,9 +1329,9 @@ UniValue getsnapshot(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue getaddresstxids(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
if (fHelp || params.size() > 2)
|
||||
throw runtime_error(
|
||||
"getaddresstxids\n"
|
||||
"getaddresstxids (ccvout)\n"
|
||||
"\nReturns the txids for an address(es) (requires addressindex to be enabled).\n"
|
||||
"\nArguments:\n"
|
||||
"{\n"
|
||||
@@ -1315,14 +1343,15 @@ UniValue getaddresstxids(const UniValue& params, bool fHelp)
|
||||
" \"start\" (number) The start block height\n"
|
||||
" \"end\" (number) The end block height\n"
|
||||
"}\n"
|
||||
"\nCCvout (optional) Return CCvouts instead of normal vouts\n"
|
||||
"\nResult:\n"
|
||||
"[\n"
|
||||
" \"transactionid\" (string) The transaction id\n"
|
||||
" ,...\n"
|
||||
"]\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getaddresstxids", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'")
|
||||
+ HelpExampleRpc("getaddresstxids", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}")
|
||||
+ HelpExampleCli("getaddresstxids", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}' (ccvout)")
|
||||
+ HelpExampleRpc("getaddresstxids", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]} (ccvout)")
|
||||
);
|
||||
|
||||
std::vector<std::pair<uint160, int> > addresses;
|
||||
|
||||
@@ -203,7 +203,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
|
||||
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
|
||||
else if (tx.IsCoinImport()) {
|
||||
in.push_back(Pair("is_import", "1"));
|
||||
TxProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; CTxDestination importaddress;
|
||||
ImportProof proof; CTransaction burnTx; std::vector<CTxOut> payouts; CTxDestination importaddress;
|
||||
if (UnmarshalImportTx(tx, proof, burnTx, payouts))
|
||||
{
|
||||
if (burnTx.vout.size() == 0)
|
||||
|
||||
@@ -350,9 +350,13 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "crosschain", "getNotarisationsForBlock", &getNotarisationsForBlock, true },
|
||||
{ "crosschain", "scanNotarisationsDB", &scanNotarisationsDB, true },
|
||||
{ "crosschain", "getimports", &getimports, true },
|
||||
{ "crosschain", "getwalletburntransactions", &getwalletburntransactions, true },
|
||||
{ "crosschain", "migrate_converttoexport", &migrate_converttoexport, true },
|
||||
{ "crosschain", "migrate_createburntransaction", &migrate_createburntransaction, true },
|
||||
{ "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true },
|
||||
{ "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true },
|
||||
{ "crosschain", "migrate_checkburntransactionsource", &migrate_checkburntransactionsource, true },
|
||||
{ "crosschain", "migrate_createnotaryapprovaltransaction", &migrate_createnotaryapprovaltransaction, true },
|
||||
{ "crosschain", "selfimport", &selfimport, true },
|
||||
{ "crosschain", "importdual", &importdual, true },
|
||||
//ImportGateway
|
||||
|
||||
@@ -478,9 +478,13 @@ extern UniValue crosschainproof(const UniValue& params, bool fHelp);
|
||||
extern UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp);
|
||||
extern UniValue scanNotarisationsDB(const UniValue& params, bool fHelp);
|
||||
extern UniValue getimports(const UniValue& params, bool fHelp);
|
||||
extern UniValue getwalletburntransactions(const UniValue& params, bool fHelp);
|
||||
extern UniValue migrate_converttoexport(const UniValue& params, bool fHelp);
|
||||
extern UniValue migrate_createburntransaction(const UniValue& params, bool fHelp);
|
||||
extern UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp);
|
||||
extern UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp);
|
||||
extern UniValue migrate_checkburntransactionsource(const UniValue& params, bool fHelp);
|
||||
extern UniValue migrate_createnotaryapprovaltransaction(const UniValue& params, bool fHelp);
|
||||
|
||||
extern UniValue notaries(const UniValue& params, bool fHelp);
|
||||
extern UniValue minerids(const UniValue& params, bool fHelp);
|
||||
|
||||
@@ -31,6 +31,17 @@ CScheduler::CScheduler() : nThreadsServicingQueue(0), stopRequested(false), stop
|
||||
|
||||
CScheduler::~CScheduler()
|
||||
{
|
||||
/*int32_t i;
|
||||
if ( nThreadsServicingQueue != 0 )
|
||||
{
|
||||
for (i=0; i<10; i++)
|
||||
{
|
||||
sleep(1);
|
||||
fprintf(stderr,"CScheduler nThreadsServicingQueue.%d\n",(int32_t)nThreadsServicingQueue);
|
||||
if ( nThreadsServicingQueue == 0 )
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
assert(nThreadsServicingQueue == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ int32_t ASSETCHAINS_LWMAPOS = 0;
|
||||
int32_t VERUS_BLOCK_POSUNITS = 1000;
|
||||
int32_t ASSETCHAINS_OVERWINTER = 227520;
|
||||
int32_t ASSETCHAINS_SAPLING = 227520;
|
||||
int32_t KOMODO_TESTNODE = 0;
|
||||
|
||||
unsigned int MAX_BLOCK_SIGOPS = 20000;
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <thread>
|
||||
|
||||
#include "paymentdisclosuredb.h"
|
||||
int32_t komodo_blockheight(uint256 hash);
|
||||
|
||||
using namespace libzcash;
|
||||
|
||||
@@ -677,7 +678,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
||||
if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString()));
|
||||
}
|
||||
wtxHeight = mapBlockIndex[wtx.hashBlock]->GetHeight();
|
||||
wtxHeight = komodo_blockheight(wtx.hashBlock);
|
||||
wtxDepth = wtx.GetDepthInMainChain();
|
||||
}
|
||||
LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
|
||||
|
||||
@@ -55,6 +55,7 @@ using namespace libzcash;
|
||||
extern char ASSETCHAINS_SYMBOL[65];
|
||||
|
||||
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
|
||||
int32_t komodo_blockheight(uint256 hash);
|
||||
int tx_height( const uint256 &hash );
|
||||
extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
|
||||
extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
|
||||
@@ -836,7 +837,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||
if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString()));
|
||||
}
|
||||
wtxHeight = mapBlockIndex[wtx.hashBlock]->GetHeight();
|
||||
wtxHeight = komodo_blockheight(wtx.hashBlock);
|
||||
wtxDepth = wtx.GetDepthInMainChain();
|
||||
}
|
||||
LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
|
||||
|
||||
@@ -94,14 +94,15 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (fHelp || params.size() < 1 || params.size() > 3)
|
||||
if (fHelp || params.size() < 1 || params.size() > 4)
|
||||
throw runtime_error(
|
||||
"importprivkey \"komodoprivkey\" ( \"label\" rescan )\n"
|
||||
"importprivkey \"komodoprivkey\" ( \"label\" rescan height)\n"
|
||||
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"komodoprivkey\" (string, required) The private key (see dumpprivkey)\n"
|
||||
"2. \"label\" (string, optional, default=\"\") An optional label\n"
|
||||
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
|
||||
"4. height (integer, optional, default=0) start at block height?\n"
|
||||
"\nNote: This call can take minutes to complete if rescan is true.\n"
|
||||
"\nExamples:\n"
|
||||
"\nDump a private key\n"
|
||||
@@ -111,7 +112,11 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||
"\nImport using a label and without rescan\n"
|
||||
+ HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
|
||||
"\nAs a JSON-RPC call\n"
|
||||
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
|
||||
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false") +
|
||||
"\nImport with rescan from a block height\n"
|
||||
+ HelpExampleCli("importprivkey", "\"mykey\" \"testing\" true 1000") +
|
||||
"\nAs a JSON-RPC call\n"
|
||||
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", true, 1000")
|
||||
);
|
||||
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
@@ -120,6 +125,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||
|
||||
string strSecret = params[0].get_str();
|
||||
string strLabel = "";
|
||||
int32_t height = 0;
|
||||
if (params.size() > 1)
|
||||
strLabel = params[1].get_str();
|
||||
|
||||
@@ -127,7 +133,12 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||
bool fRescan = true;
|
||||
if (params.size() > 2)
|
||||
fRescan = params[2].get_bool();
|
||||
if ( fRescan && params.size() == 4 )
|
||||
height = params[3].get_int();
|
||||
|
||||
if ( height < 0 || height > chainActive.Height() )
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan height is out of range.");
|
||||
|
||||
CKey key = DecodeSecret(strSecret);
|
||||
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
|
||||
|
||||
@@ -152,7 +163,7 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
|
||||
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
||||
|
||||
if (fRescan) {
|
||||
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
|
||||
pwalletMain->ScanForWalletTransactions(chainActive[height], true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,10 +122,10 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
|
||||
entry.push_back(Pair("generated", true));
|
||||
if (confirms > 0)
|
||||
{
|
||||
entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)mapBlockIndex[wtx.hashBlock]->GetHeight(),confirms)));
|
||||
entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)komodo_blockheight(wtx.hashBlock),confirms)));
|
||||
entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
|
||||
entry.push_back(Pair("blockindex", wtx.nIndex));
|
||||
entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
|
||||
entry.push_back(Pair("blocktime", (uint64_t)komodo_blocktime(wtx.hashBlock)));
|
||||
entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
|
||||
} else entry.push_back(Pair("confirmations", confirms));
|
||||
uint256 hash = wtx.GetHash();
|
||||
@@ -1624,7 +1624,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
|
||||
tallyitem& item = mapTally[address];
|
||||
item.nAmount += txout.nValue; // komodo_interest?
|
||||
item.nConf = min(item.nConf, nDepth);
|
||||
item.nHeight = mapBlockIndex[wtx.hashBlock]->GetHeight();
|
||||
item.nHeight = komodo_blockheight(wtx.hashBlock);
|
||||
item.txids.push_back(wtx.GetHash());
|
||||
if (mine & ISMINE_WATCH_ONLY)
|
||||
item.fIsWatchonly = true;
|
||||
@@ -6594,6 +6594,7 @@ UniValue gatewayspartialsign(const UniValue& params, bool fHelp)
|
||||
coin = params[1].get_str();
|
||||
parthex = params[2].get_str();
|
||||
hex = GatewaysPartialSign(0,txid,coin,parthex);
|
||||
RETURN_IF_ERROR(CCerror);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "utiltime.h"
|
||||
#include "wallet/wallet.h"
|
||||
#include "zcash/Proof.hpp"
|
||||
#include "komodo_defs.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
@@ -486,7 +487,6 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
if (!(CheckTransaction(0,wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()))
|
||||
{
|
||||
fprintf(stderr, "Removing corrupt tx from wallet.%s\n", hash.ToString().c_str());
|
||||
deadTxns.push_back(hash);
|
||||
return false;
|
||||
}
|
||||
@@ -951,22 +951,35 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
result = DB_CORRUPT;
|
||||
}
|
||||
|
||||
if (!deadTxns.empty())
|
||||
if ( !deadTxns.empty() )
|
||||
{
|
||||
int32_t reAdded = 0;
|
||||
BOOST_FOREACH (uint256& hash, deadTxns) {
|
||||
if (!EraseTx(hash))
|
||||
fprintf(stderr, "could not delete tx.%s\n",hash.ToString().c_str());
|
||||
uint256 blockhash; CTransaction tx;
|
||||
if (GetTransaction(hash,tx,blockhash,true))
|
||||
if ( ASSETCHAINS_STAKED != 0 )
|
||||
{
|
||||
int32_t reAdded = 0;
|
||||
CWalletDB walletdb(pwallet->strWalletFile, "r+", false);
|
||||
BOOST_FOREACH (uint256& hash, deadTxns)
|
||||
{
|
||||
CWalletTx wtx(pwallet,tx);
|
||||
pwallet->AddToWallet(wtx, true, NULL);
|
||||
reAdded++;
|
||||
fprintf(stderr, "Removing corrupt tx from wallet.%s\n", hash.ToString().c_str());
|
||||
if (!EraseTx(hash))
|
||||
fprintf(stderr, "could not delete tx.%s\n",hash.ToString().c_str());
|
||||
uint256 blockhash; CTransaction tx;
|
||||
if (GetTransaction(hash,tx,blockhash,true))
|
||||
{
|
||||
CWalletTx wtx(pwallet,tx);
|
||||
pwallet->AddToWallet(wtx, false, &walletdb);
|
||||
reAdded++;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Cleared %lu corrupted transactions from wallet. Readded %i known transactions.\n",(long)deadTxns.size(),reAdded);
|
||||
fNoncriticalErrors = false;
|
||||
deadTxns.clear();
|
||||
}
|
||||
else if ( (GetBoolArg("-zapwallettxes", false)) )
|
||||
{
|
||||
LogPrintf("Transactions are corrupted. Please restart daemon with -zapwallettxes=2\n");
|
||||
fprintf(stderr,"Transactions are corrupted. Please restart daemon with -zapwallettxes=2\n");
|
||||
return DB_CORRUPT;
|
||||
}
|
||||
fprintf(stderr, "Cleared %lu corrupted transactions from wallet. Readded %i known transactions.\n",(long)deadTxns.size(),reAdded);
|
||||
deadTxns.clear();
|
||||
}
|
||||
|
||||
if (fNoncriticalErrors && result == DB_LOAD_OK)
|
||||
|
||||
@@ -16,6 +16,11 @@ bool CZMQAbstractNotifier::NotifyBlock(const CBlockIndex * /*CBlockIndex*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyBlock(const CBlock &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CZMQAbstractNotifier::NotifyTransaction(const CTransaction &/*transaction*/)
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
virtual bool NotifyBlock(const CBlockIndex *pindex);
|
||||
virtual bool NotifyBlock(const CBlock& pblock);
|
||||
virtual bool NotifyTransaction(const CTransaction &transaction);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -39,6 +39,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const
|
||||
factories["pubhashtx"] = CZMQAbstractNotifier::Create<CZMQPublishHashTransactionNotifier>;
|
||||
factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
|
||||
factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
|
||||
factories["pubcheckedblock"] = CZMQAbstractNotifier::Create<CZMQPublishCheckedBlockNotifier>;
|
||||
|
||||
for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
|
||||
{
|
||||
@@ -141,6 +142,27 @@ void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex)
|
||||
}
|
||||
}
|
||||
|
||||
void CZMQNotificationInterface::BlockChecked(const CBlock& block, const CValidationState& state)
|
||||
{
|
||||
if (state.IsInvalid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
|
||||
{
|
||||
CZMQAbstractNotifier *notifier = *i;
|
||||
if (notifier->NotifyBlock(block))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
notifier->Shutdown();
|
||||
i = notifiers.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CZMQNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlock *pblock)
|
||||
{
|
||||
for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
|
||||
|
||||
#include "validationinterface.h"
|
||||
#include "consensus/validation.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
@@ -26,6 +27,7 @@ protected:
|
||||
// CValidationInterface
|
||||
void SyncTransaction(const CTransaction &tx, const CBlock *pblock);
|
||||
void UpdatedBlockTip(const CBlockIndex *pindex);
|
||||
void BlockChecked(const CBlock& block, const CValidationState& state);
|
||||
|
||||
private:
|
||||
CZMQNotificationInterface();
|
||||
|
||||
@@ -12,6 +12,7 @@ static const char *MSG_HASHBLOCK = "hashblock";
|
||||
static const char *MSG_HASHTX = "hashtx";
|
||||
static const char *MSG_RAWBLOCK = "rawblock";
|
||||
static const char *MSG_RAWTX = "rawtx";
|
||||
static const char *MSG_CHECKEDBLOCK = "checkedblock";
|
||||
|
||||
// Internal function to send multipart message
|
||||
static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
|
||||
@@ -179,6 +180,19 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
|
||||
return SendMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());
|
||||
}
|
||||
|
||||
bool CZMQPublishCheckedBlockNotifier::NotifyBlock(const CBlock& block)
|
||||
{
|
||||
LogPrint("zmq", "zmq: Publish checkedblock %s\n", block.GetHash().GetHex());
|
||||
|
||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||
{
|
||||
LOCK(cs_main);
|
||||
ss << block;
|
||||
}
|
||||
|
||||
return SendMessage(MSG_CHECKEDBLOCK, &(*ss.begin()), ss.size());
|
||||
}
|
||||
|
||||
bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
|
||||
{
|
||||
uint256 hash = transaction.GetHash();
|
||||
|
||||
@@ -52,4 +52,10 @@ public:
|
||||
bool NotifyTransaction(const CTransaction &transaction);
|
||||
};
|
||||
|
||||
class CZMQPublishCheckedBlockNotifier : public CZMQAbstractPublishNotifier
|
||||
{
|
||||
public:
|
||||
bool NotifyBlock(const CBlock &block);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
|
||||
|
||||
Reference in New Issue
Block a user