cross chain rpc methods

This commit is contained in:
Scott Sadler
2018-05-18 19:29:33 -03:00
parent 06c960d2b7
commit e4f943d86d
18 changed files with 264 additions and 305 deletions

View File

@@ -279,6 +279,7 @@ libbitcoin_server_a_SOURCES = \
pow.cpp \ pow.cpp \
rest.cpp \ rest.cpp \
rpcblockchain.cpp \ rpcblockchain.cpp \
rpccrosschain.cpp \
rpcmining.cpp \ rpcmining.cpp \
rpcmisc.cpp \ rpcmisc.cpp \
rpcnet.cpp \ rpcnet.cpp \

View File

@@ -154,7 +154,7 @@ uint32_t Eval::GetCurrentLedgerID() const
/* /*
* Get MoM from a notarisation tx hash * Get MoM from a notarisation tx hash (on KMD)
*/ */
bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) const bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) const
{ {
@@ -166,9 +166,11 @@ bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data)
return true; return true;
} }
bool Eval::GetNotarisationData(int notarisationHeight, NotarisationData &data, bool verifyCanonical) const /*
* Get MoMoM corresponding to a notarisation tx hash (on assetchain)
*/
bool Eval::GetProofRoot(uint256 kmdNotarisationHash, uint256 &momom) const
{ {
return false;
} }

View File

@@ -72,8 +72,7 @@ public:
virtual bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const; virtual bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const;
virtual int32_t GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const; virtual int32_t GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const;
virtual bool GetNotarisationData(uint256 notarisationHash, NotarisationData &data) const; virtual bool GetNotarisationData(uint256 notarisationHash, NotarisationData &data) const;
virtual bool GetNotarisationData(int notarisationHeight, NotarisationData &data, virtual bool GetProofRoot(uint256 kmdNotarisationHash, uint256 &momom) const;
bool verifyCanonical) const;
virtual bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const; virtual bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const;
virtual uint32_t GetCurrentLedgerID() const; virtual uint32_t GetCurrentLedgerID() const;
}; };
@@ -228,6 +227,9 @@ public:
}; };
typedef std::pair<uint256,MerkleBranch> TxProof;
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves); uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves);

View File

@@ -15,7 +15,7 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &imp
if (importTx.vout.size() == 0) return Invalid("no-vouts"); if (importTx.vout.size() == 0) return Invalid("no-vouts");
// params // params
MomoProof proof; TxProof proof;
CTransaction burnTx; CTransaction burnTx;
if (!E_UNMARSHAL(params, ss >> proof; ss >> burnTx)) if (!E_UNMARSHAL(params, ss >> proof; ss >> burnTx))
return Invalid("invalid-params"); return Invalid("invalid-params");
@@ -56,11 +56,11 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &imp
// Check proof confirms existance of burnTx // Check proof confirms existance of burnTx
{ {
NotarisationData data(1); uint256 momom;
if (!GetNotarisationData(proof.notarisationHeight, data, true)) if (!GetProofRoot(proof.first, momom))
return Invalid("coudnt-load-momom"); return Invalid("coudnt-load-momom");
if (data.MoMoM != proof.branch.Exec(burnTx.GetHash())) if (momom != proof.second.Exec(burnTx.GetHash()))
return Invalid("momom-check-fail"); return Invalid("momom-check-fail");
} }

View File

@@ -5,29 +5,33 @@
/* On KMD */ /* On KMD */
uint256 GetProofRoot(char* symbol, uint32_t targetCCid, int kmdHeight, std::vector<uint256> &moms, int* assetChainHeight) uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeight,
std::vector<uint256> &moms, uint256 &destNotarisationTxid)
{ {
/* /*
* Notaries don't wait for confirmation on KMD before performing a backnotarisation, * Notaries don't wait for confirmation on KMD before performing a backnotarisation,
* but we need a determinable range that will encompass all merkle roots. Include MoMs * but we need a determinable range that will encompass all merkle roots. Include MoMs
* including the block height of the last notarisation until the height before the * including the block height of the last notarisation until the height before the
* previous notarisation. * previous notarisation.
*
* kmdHeight notarisations-0 notarisations-1
* | |********************|
* > scan backwards >
*/ */
*assetChainHeight = -1;
if (targetCCid <= 1) if (targetCCid <= 1)
return uint256(); return uint256();
int seenOwnNotarisations = 0; if (kmdHeight < 0 || kmdHeight > chainActive.Height())
return uint256();
// TODO: test height out of range int seenOwnNotarisations = 0;
// TODO: Make sure that boundary for moms is notarisation tx not block
for (int i=0; i<1440; i++) { for (int i=0; i<1440; i++) {
if (i > kmdHeight) break; if (i > kmdHeight) break;
NotarisationsInBlock notarisations; NotarisationsInBlock notarisations;
uint256 blockHash = *chainActive[kmdHeight-i]->phashBlock; uint256 blockHash = *chainActive[kmdHeight-i]->phashBlock;
if (!pnotarisations->Read(blockHash, notarisations)) if (!GetBlockNotarisations(blockHash, notarisations))
continue; continue;
BOOST_FOREACH(Notarisation& nota, notarisations) { BOOST_FOREACH(Notarisation& nota, notarisations) {
NotarisationData& data = nota.second; NotarisationData& data = nota.second;
@@ -36,32 +40,24 @@ uint256 GetProofRoot(char* symbol, uint32_t targetCCid, int kmdHeight, std::vect
if (strcmp(data.symbol, symbol) == 0) if (strcmp(data.symbol, symbol) == 0)
{ {
seenOwnNotarisations++; seenOwnNotarisations++;
printf("seenOwnNotarisations:%i\n", seenOwnNotarisations);
if (seenOwnNotarisations == 2) if (seenOwnNotarisations == 2)
goto end; goto end;
if (seenOwnNotarisations == 1) if (seenOwnNotarisations == 1)
*assetChainHeight = data.height; // TODO: Needed? destNotarisationTxid = nota.first;
} }
if (seenOwnNotarisations == 1) { if (seenOwnNotarisations == 1)
moms.push_back(data.MoM); moms.push_back(data.MoM);
printf("Pushed a MoM@%i:%s\n", kmdHeight-i, data.MoM.GetHex().data());
}
} }
} }
end: end:
printf("GetProofRoot {\n");
printf(" CC:%i S:%s H:%i\n", targetCCid, symbol, kmdHeight);
for (int i=0; i<moms.size(); i++) printf(" %s", moms[i].GetHex().data());
printf("\n R:%s\n", GetMerkleRoot(moms).GetHex().data());
printf("}\n");
return GetMerkleRoot(moms); return GetMerkleRoot(moms);
} }
/* On KMD */ /* On KMD */
MerkleBranch GetCrossChainProof(uint256 txid, char* targetSymbol, TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
uint32_t targetCCid, uint256 notarisationTxid, MerkleBranch assetChainProof) const TxProof assetChainProof)
{ {
/* /*
* Here we are given a proof generated by an assetchain A which goes from given txid to * Here we are given a proof generated by an assetchain A which goes from given txid to
@@ -70,7 +66,7 @@ MerkleBranch GetCrossChainProof(uint256 txid, char* targetSymbol,
* that range, and finally extend the proof to lead to the MoMoM (proof root). * that range, and finally extend the proof to lead to the MoMoM (proof root).
*/ */
EvalRef eval; EvalRef eval;
uint256 MoM = assetChainProof.Exec(txid); uint256 MoM = assetChainProof.second.Exec(txid);
// Get a kmd height for given notarisation Txid // Get a kmd height for given notarisation Txid
int kmdHeight; int kmdHeight;
@@ -78,9 +74,9 @@ MerkleBranch GetCrossChainProof(uint256 txid, char* targetSymbol,
CTransaction sourceNotarisation; CTransaction sourceNotarisation;
uint256 hashBlock; uint256 hashBlock;
CBlockIndex blockIdx; CBlockIndex blockIdx;
if (eval->GetTxConfirmed(notarisationTxid, sourceNotarisation, blockIdx)) if (eval->GetTxConfirmed(assetChainProof.first, sourceNotarisation, blockIdx))
kmdHeight = blockIdx.nHeight; kmdHeight = blockIdx.nHeight;
else if (eval->GetTxUnconfirmed(notarisationTxid, sourceNotarisation, hashBlock)) else if (eval->GetTxUnconfirmed(assetChainProof.first, sourceNotarisation, hashBlock))
kmdHeight = chainActive.Tip()->nHeight; kmdHeight = chainActive.Tip()->nHeight;
else else
throw std::runtime_error("Notarisation not found"); throw std::runtime_error("Notarisation not found");
@@ -88,16 +84,14 @@ MerkleBranch GetCrossChainProof(uint256 txid, char* targetSymbol,
// Get MoMs for kmd height and symbol // Get MoMs for kmd height and symbol
std::vector<uint256> moms; std::vector<uint256> moms;
int targetChainStartHeight; uint256 targetChainNotarisationTxid;
printf("Getting Proof Root\n"); uint256 MoMoM = CalculateProofRoot(targetSymbol, targetCCid, kmdHeight, moms, targetChainNotarisationTxid);
uint256 MoMoM = GetProofRoot(targetSymbol, targetCCid, kmdHeight, moms, &targetChainStartHeight);
if (MoMoM.IsNull()) if (MoMoM.IsNull())
throw std::runtime_error("No MoMs found"); throw std::runtime_error("No MoMs found");
// Find index of source MoM in MoMoM // Find index of source MoM in MoMoM
int nIndex; int nIndex;
for (nIndex=0; nIndex<moms.size(); nIndex++) { for (nIndex=0; nIndex<moms.size(); nIndex++) {
printf("findMoM: %s == %s\n", moms[nIndex].GetHex().data(), MoM.GetHex().data());
if (moms[nIndex] == MoM) if (moms[nIndex] == MoM)
goto cont; goto cont;
} }
@@ -105,7 +99,7 @@ MerkleBranch GetCrossChainProof(uint256 txid, char* targetSymbol,
cont: cont:
// Create a branch // Create a branch
std::vector<uint256> newBranch; std::vector<uint256> vBranch;
{ {
CBlock fakeBlock; CBlock fakeBlock;
for (int i=0; i<moms.size(); i++) { for (int i=0; i<moms.size(); i++) {
@@ -114,39 +108,48 @@ cont:
memcpy((void*)&fakeTx, moms[i].begin(), 32); memcpy((void*)&fakeTx, moms[i].begin(), 32);
fakeBlock.vtx.push_back(fakeTx); fakeBlock.vtx.push_back(fakeTx);
} }
newBranch = fakeBlock.GetMerkleBranch(nIndex); vBranch = fakeBlock.GetMerkleBranch(nIndex);
} }
// Concatenate branches // Concatenate branches
MerkleBranch newProof = assetChainProof; MerkleBranch newBranch = assetChainProof.second;
newProof << MerkleBranch(nIndex, newBranch); newBranch << MerkleBranch(nIndex, vBranch);
// Check proof // Check proof
printf("GetCrossChainProof {\n txid: %s\n momom: %s\n", txid.GetHex().data(), MoMoM.GetHex().data()); if (newBranch.Exec(txid) != MoMoM)
printf(" idx: %i\n", newProof.nIndex);
for (int i=0; i<newProof.branch.size(); i++) printf(" %s", newProof.branch[i].GetHex().data());
printf("\n}\n");
if (newProof.Exec(txid) != MoMoM)
throw std::runtime_error("Proof check failed"); throw std::runtime_error("Proof check failed");
return newProof; return std::make_pair(targetChainNotarisationTxid,newBranch);
} }
struct notarized_checkpoint *komodo_npptr_at(int idx);
struct notarized_checkpoint *komodo_npptr_for_height(int32_t height, int *idx);
/* On assetchain */ /* On assetchain */
bool ValidateCrossChainProof(uint256 txid, int notarisationHeight, MerkleBranch proof) bool GetNextBacknotarisation(uint256 kmdNotarisationTxid, std::pair<uint256,NotarisationData> &out)
{ {
/* /*
* Here we are given a notarisation txid, and a proof. * Here we are given a txid, and a proof.
* We go from the notarisation to get the backnotarisation, and verify the proof * We go from the KMD notarisation txid to the backnotarisation,
* against the MoMoM it contains. * then jump to the next backnotarisation, which contains the corresponding MoMoM.
*/ */
Notarisation bn;
if (!GetBackNotarisation(kmdNotarisationTxid, bn))
return false;
int npIdx;
struct notarized_checkpoint* np = komodo_npptr_for_height(bn.second.height, &npIdx);
if (!(np = komodo_npptr_at(npIdx+1)))
return false;
return GetBackNotarisation(np->notarized_desttxid, out);
throw std::runtime_error("Can't get backnotarisation");
} }
struct notarized_checkpoint* komodo_npptr(int32_t height);
struct notarized_checkpoint* komodo_npptr_for_height(int32_t height, int *idx);
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_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);
@@ -155,7 +158,7 @@ int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_
* in: txid * in: txid
* out: pair<notarisationTxHash,merkleBranch> * out: pair<notarisationTxHash,merkleBranch>
*/ */
std::pair<uint256,MerkleBranch> GetAssetchainProof(uint256 hash, int &npIdx) TxProof GetAssetchainProof(uint256 hash)
{ {
int nIndex; int nIndex;
CBlockIndex* blockIndex; CBlockIndex* blockIndex;
@@ -169,11 +172,10 @@ std::pair<uint256,MerkleBranch> GetAssetchainProof(uint256 hash, int &npIdx)
throw std::runtime_error("cannot find transaction"); throw std::runtime_error("cannot find transaction");
blockIndex = mapBlockIndex[blockHash]; blockIndex = mapBlockIndex[blockHash];
if (!(np = komodo_npptr_for_height(blockIndex->nHeight, &npIdx))) if (!(np = komodo_npptr(blockIndex->nHeight)))
throw std::runtime_error("notarisation not found"); throw std::runtime_error("notarisation not found");
// index of block in MoM leaves // index of block in MoM leaves
printf("notarised at: %i\n", np->notarized_height);
nIndex = np->notarized_height - blockIndex->nHeight; nIndex = np->notarized_height - blockIndex->nHeight;
} }

View File

@@ -5,17 +5,18 @@
/* On assetchain */ /* On assetchain */
std::pair<uint256,MerkleBranch> GetAssetchainProof(uint256 hash, int &npIdx); TxProof GetAssetchainProof(uint256 hash);
/* On KMD */ /* On KMD */
uint256 GetProofRoot(char* symbol, uint32_t targetCCid, int kmdHeight, std::vector<uint256> &moms, int* assetChainHeight); uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeight,
std::vector<uint256> &moms, uint256 &destNotarisationTxid);
/* On KMD */ /* On KMD */
MerkleBranch GetCrossChainProof(uint256 txid, char* targetSymbol, TxProof GetCrossChainProof(const uint256 txid, const char* targetSymbol, uint32_t targetCCid,
uint32_t targetCCid, uint256 notarisationTxid, MerkleBranch assetChainProof); const TxProof assetChainProof);
/* On assetchain */ /* On assetchain */
bool ValidateCrossChainProof(uint256 txid, int notarisationHeight, MerkleBranch proof); bool GetNextBacknotarisation(uint256 txid, std::pair<uint256,NotarisationData> &bn);
#endif /* CROSSCHAIN_H */ #endif /* CROSSCHAIN_H */

View File

@@ -13,7 +13,7 @@
* import. If it doesn't contain this it's invalid. The empty OP_RETURN will hang around * import. If it doesn't contain this it's invalid. The empty OP_RETURN will hang around
* in the UTXO set and the transaction will be detected as a duplicate. * in the UTXO set and the transaction will be detected as a duplicate.
*/ */
CTransaction MakeImportCoinTransaction(const MomoProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts) CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts)
{ {
std::vector<uint8_t> payload = std::vector<uint8_t> payload =
E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << proof; ss << burnTx); E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << proof; ss << burnTx);
@@ -30,7 +30,7 @@ CTxOut MakeBurnOutput(CAmount value, int targetChain, const std::vector<CTxOut>
} }
static bool UnmarshalImportTx(const CTransaction &importTx, MomoProof &proof, CTransaction &burnTx) static bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx)
{ {
CScript scriptSig = importTx.vin[0].scriptSig; CScript scriptSig = importTx.vin[0].scriptSig;
auto pc = scriptSig.begin(); auto pc = scriptSig.begin();
@@ -51,7 +51,7 @@ static bool UnmarshalImportTx(const CTransaction &importTx, MomoProof &proof, CT
*/ */
CAmount GetCoinImportValue(const CTransaction &tx) CAmount GetCoinImportValue(const CTransaction &tx)
{ {
MomoProof proof; TxProof proof;
CTransaction burnTx; CTransaction burnTx;
if (UnmarshalImportTx(tx, proof, burnTx)) { if (UnmarshalImportTx(tx, proof, burnTx)) {
return burnTx.vout.size() ? burnTx.vout[0].nValue : 0; return burnTx.vout.size() ? burnTx.vout[0].nValue : 0;

View File

@@ -8,22 +8,9 @@
#include <cryptoconditions.h> #include <cryptoconditions.h>
class MomoProof
{
public:
MerkleBranch branch;
int notarisationHeight;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(branch);
READWRITE(notarisationHeight);
}
};
CAmount GetCoinImportValue(const CTransaction &tx); CAmount GetCoinImportValue(const CTransaction &tx);
CTransaction MakeImportCoinTransaction(const MomoProof proof, CTransaction MakeImportCoinTransaction(const TxProof proof,
const CTransaction burnTx, const std::vector<CTxOut> payouts); const CTransaction burnTx, const std::vector<CTxOut> payouts);
CTxOut MakeBurnOutput(CAmount value, int targetChain, const std::vector<CTxOut> payouts); CTxOut MakeBurnOutput(CAmount value, int targetChain, const std::vector<CTxOut> payouts);

View File

@@ -32,6 +32,18 @@ NotarisationsInBlock GetNotarisationsInBlock(const CBlock &block, int nHeight)
} }
bool GetBlockNotarisations(uint256 blockHash, NotarisationsInBlock &nibs)
{
return pnotarisations->Read(blockHash, nibs);
}
bool GetBackNotarisation(uint256 notarisationHash, Notarisation &n)
{
return pnotarisations->Read(notarisationHash, n);
}
/* /*
* Write an index of KMD notarisation id -> backnotarisation * Write an index of KMD notarisation id -> backnotarisation
*/ */
@@ -39,9 +51,7 @@ void WriteBackNotarisations(NotarisationsInBlock notarisations)
{ {
BOOST_FOREACH(Notarisation &n, notarisations) BOOST_FOREACH(Notarisation &n, notarisations)
{ {
if (n.second.IsBackNotarisation) { if (n.second.IsBackNotarisation)
pnotarisations->Write(n.second.txHash, n); pnotarisations->Write(n.second.txHash, n);
printf("WriteBackNotarisations {\n m3:%s\n}\n", n.second.MoMoM.GetHex().data());
}
} }
} }

View File

@@ -15,12 +15,12 @@ public:
extern NotarisationDB *pnotarisations; extern NotarisationDB *pnotarisations;
typedef std::pair<uint256,NotarisationData> Notarisation; typedef std::pair<uint256,NotarisationData> Notarisation;
typedef std::vector<Notarisation> NotarisationsInBlock; typedef std::vector<Notarisation> NotarisationsInBlock;
NotarisationsInBlock GetNotarisationsInBlock(const CBlock &block, int nHeight); NotarisationsInBlock GetNotarisationsInBlock(const CBlock &block, int nHeight);
bool GetBlockNotarisations(uint256 blockHash, NotarisationsInBlock &nibs);
bool GetBackNotarisation(uint256 notarisationHash, Notarisation &n);
void WriteBackNotarisations(NotarisationsInBlock notarisations); void WriteBackNotarisations(NotarisationsInBlock notarisations);
#endif /* NOTARISATIONDB_H */ #endif /* NOTARISATIONDB_H */

View File

@@ -761,10 +761,6 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,
//uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n); //uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n);
int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width); 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); 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);
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);
struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi);
uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
UniValue kvsearch(const UniValue& params, bool fHelp) UniValue kvsearch(const UniValue& params, bool fHelp)
{ {
@@ -801,170 +797,6 @@ UniValue kvsearch(const UniValue& params, bool fHelp)
return ret; return ret;
} }
UniValue allMoMs(const UniValue& params, bool fHelp)
{
struct komodo_ccdata_entry *allMoMs; uint256 MoMoM; int32_t num,i,kmdstarti,kmdendi; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 2 )
throw runtime_error("allMoMs kmdstarti kmdendi\n");
LOCK(cs_main);
kmdstarti = atoi(params[0].get_str().c_str());
kmdendi = atoi(params[1].get_str().c_str());
ret.push_back(Pair("kmdstarti",kmdstarti));
ret.push_back(Pair("kmdendi",kmdendi));
if ( (allMoMs= komodo_allMoMs(&num,&MoMoM,kmdstarti,kmdendi)) != 0 )
{
for (i=0; i<num; i++)
{
UniValue item(UniValue::VOBJ);
item.push_back(Pair("MoM",allMoMs[i].MoM.ToString()));
item.push_back(Pair("coin",allMoMs[i].symbol));
item.push_back(Pair("notarized_height",allMoMs[i].notarized_height));
item.push_back(Pair("kmdheight",allMoMs[i].kmdheight));
item.push_back(Pair("txi",allMoMs[i].txi));
a.push_back(item);
}
ret.push_back(Pair("MoMs",a));
ret.push_back(Pair("MoMoM",MoMoM.ToString()));
ret.push_back(Pair("MoMoMdepth",(int)num));
free(allMoMs);
}
return(ret);
}
UniValue MoMoMdata(const UniValue& params, bool fHelp)
{
char *symbol,hexstr[16384+1]; struct komodo_ccdataMoMoM mdata; int32_t i,kmdheight,notarized_height; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 3 )
throw runtime_error("MoMoMdata symbol kmdheight notarized_height\n");
LOCK(cs_main);
symbol = (char *)params[0].get_str().c_str();
kmdheight = atoi(params[1].get_str().c_str());
notarized_height = atoi(params[2].get_str().c_str());
ret.push_back(Pair("coin",symbol));
ret.push_back(Pair("kmdheight",kmdheight));
ret.push_back(Pair("notarized_height",notarized_height));
memset(&mdata,0,sizeof(mdata));
if ( komodo_MoMoMdata(hexstr,sizeof(hexstr),&mdata,symbol,kmdheight,notarized_height) == 0 )
{
ret.push_back(Pair("kmdstarti",mdata.kmdstarti));
ret.push_back(Pair("kmdendi",mdata.kmdendi));
ret.push_back(Pair("MoMoM",mdata.MoMoM.ToString()));
ret.push_back(Pair("MoMoMdepth",mdata.MoMoMdepth));
ret.push_back(Pair("numnotarizations",mdata.numpairs));
if ( mdata.pairs != 0 )
{
//fprintf(stderr,"mdata.pairs free %p, numpairs.%d\n",mdata.pairs,mdata.numpairs);
for (i=0; i<mdata.numpairs; i++)
{
UniValue item(UniValue::VOBJ);
item.push_back(Pair("height",(int)mdata.pairs[i].notarized_height));
item.push_back(Pair("MoMoMoffset",(int)mdata.pairs[i].MoMoMoffset));
a.push_back(item);
}
free(mdata.pairs);
}
ret.push_back(Pair("notarizations",a));
ret.push_back(Pair("data",hexstr));
} else ret.push_back(Pair("error","cant calculate MoMoM"));
return(ret);
}
UniValue calc_MoM(const UniValue& params, bool fHelp)
{
int32_t height,MoMdepth; uint256 MoM; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 2 )
throw runtime_error("calc_MoM height MoMdepth\n");
LOCK(cs_main);
height = atoi(params[0].get_str().c_str());
MoMdepth = atoi(params[1].get_str().c_str());
if ( height <= 0 || MoMdepth <= 0 || MoMdepth >= height )
throw runtime_error("calc_MoM illegal height or MoMdepth\n");
//fprintf(stderr,"height_MoM height.%d\n",height);
MoM = komodo_calcMoM(height,MoMdepth);
ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
ret.push_back(Pair("height",height));
ret.push_back(Pair("MoMdepth",MoMdepth));
ret.push_back(Pair("MoM",MoM.GetHex()));
return ret;
}
UniValue height_MoM(const UniValue& params, bool fHelp)
{
int32_t height,depth,notarized_height,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; uint256 MoM,MoMoM,kmdtxid; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 1 )
throw runtime_error("height_MoM height\n");
LOCK(cs_main);
height = atoi(params[0].get_str().c_str());
if ( height <= 0 )
{
if ( chainActive.Tip() == 0 )
{
ret.push_back(Pair("error",(char *)"no active chain yet"));
return(ret);
}
height = chainActive.Tip()->nHeight;
}
//fprintf(stderr,"height_MoM height.%d\n",height);
depth = komodo_MoM(&notarized_height,&MoM,&kmdtxid,height,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi);
ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
ret.push_back(Pair("height",height));
ret.push_back(Pair("timestamp",(uint64_t)timestamp));
if ( depth > 0 )
{
ret.push_back(Pair("depth",depth));
ret.push_back(Pair("notarized_height",notarized_height));
ret.push_back(Pair("MoM",MoM.GetHex()));
ret.push_back(Pair("kmdtxid",kmdtxid.GetHex()));
if ( ASSETCHAINS_SYMBOL[0] != 0 )
{
ret.push_back(Pair("MoMoM",MoMoM.GetHex()));
ret.push_back(Pair("MoMoMoffset",MoMoMoffset));
ret.push_back(Pair("MoMoMdepth",MoMoMdepth));
ret.push_back(Pair("kmdstarti",kmdstarti));
ret.push_back(Pair("kmdendi",kmdendi));
}
} else ret.push_back(Pair("error",(char *)"no MoM for height"));
return ret;
}
UniValue txMoMproof(const UniValue& params, bool fHelp)
{
uint256 hash, notarisationHash, MoM,MoMoM; int32_t notarisedHeight, depth; CBlockIndex* blockIndex;
std::vector<uint256> branch;
int nIndex,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi;
// parse params and get notarisation data for tx
if ( fHelp || params.size() != 1)
throw runtime_error("txMoMproof needs a txid");
hash = uint256S(params[0].get_str());
int npIdx;
std::vector<uint8_t> proofData = E_MARSHAL(ss << GetAssetchainProof(hash, npIdx));
return HexStr(proofData);
}
UniValue getproofroot(const UniValue& params, bool fHelp)
{
std::string symbol;
int kmdHeight;
// parse params and get notarisation data for tx
if ( fHelp || params.size() != 2)
throw runtime_error("getproofroot needs a symbol and a kmdHeight");
symbol = params[0].get_str();
kmdHeight = atoi(params[0].get_str().c_str());
if (kmdHeight <= 0)
throw runtime_error("Invalid kmdHeight");
UniValue ret(UniValue::VOBJ);
return ret;
}
UniValue minerids(const UniValue& params, bool fHelp) UniValue minerids(const UniValue& params, bool fHelp)
{ {
uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); uint8_t minerids[2000],pubkeys[65][33]; int32_t i,j,n,numnotaries,tally[129]; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); uint8_t minerids[2000],pubkeys[65][33]; int32_t i,j,n,numnotaries,tally[129];

View File

@@ -136,7 +136,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "notaries", 2 }, { "notaries", 2 },
{ "height_MoM", 1 }, { "height_MoM", 1 },
{ "MoMoMdata", 3 }, { "MoMoMdata", 3 },
{ "allMoMs", 2 },
{ "txMoMproof", 1 }, { "txMoMproof", 1 },
{ "minerids", 1 }, { "minerids", 1 },
{ "kvsearch", 1 }, { "kvsearch", 1 },

158
src/rpccrosschain.cpp Normal file
View File

@@ -0,0 +1,158 @@
#include "amount.h"
#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "crosschain.h"
#include "base58.h"
#include "consensus/validation.h"
#include "cc/eval.h"
#include "main.h"
#include "primitives/transaction.h"
#include "rpcserver.h"
#include "sync.h"
#include "util.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "script/standard.h"
#include <stdint.h>
#include <univalue.h>
#include <regex>
using namespace std;
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);
struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi);
uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
UniValue assetchainproof(const UniValue& params, bool fHelp)
{
uint256 hash;
// parse params and get notarisation data for tx
if ( fHelp || params.size() != 1)
throw runtime_error("assetchainproof needs a txid");
hash = uint256S(params[0].get_str());
auto proof = GetAssetchainProof(hash);
auto proofData = E_MARSHAL(ss << proof);
return HexStr(proofData);
}
UniValue crosschainproof(const UniValue& params, bool fHelp)
{
}
UniValue getproofroot(const UniValue& params, bool fHelp)
{
std::string symbol;
int kmdHeight;
// parse params and get notarisation data for tx
if ( fHelp || params.size() != 2)
throw runtime_error("getproofroot needs a symbol and a kmdHeight");
symbol = params[0].get_str();
kmdHeight = atoi(params[0].get_str().c_str());
if (kmdHeight <= 0)
throw runtime_error("Invalid kmdHeight");
UniValue ret(UniValue::VOBJ);
return ret;
}
UniValue height_MoM(const UniValue& params, bool fHelp)
{
int32_t height,depth,notarized_height,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; uint256 MoM,MoMoM,kmdtxid; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 1 )
throw runtime_error("height_MoM height\n");
LOCK(cs_main);
height = atoi(params[0].get_str().c_str());
if ( height <= 0 )
{
if ( chainActive.Tip() == 0 )
{
ret.push_back(Pair("error",(char *)"no active chain yet"));
return(ret);
}
height = chainActive.Tip()->nHeight;
}
//fprintf(stderr,"height_MoM height.%d\n",height);
depth = komodo_MoM(&notarized_height,&MoM,&kmdtxid,height,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi);
ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
ret.push_back(Pair("height",height));
ret.push_back(Pair("timestamp",(uint64_t)timestamp));
if ( depth > 0 )
{
ret.push_back(Pair("depth",depth));
ret.push_back(Pair("notarized_height",notarized_height));
ret.push_back(Pair("MoM",MoM.GetHex()));
ret.push_back(Pair("kmdtxid",kmdtxid.GetHex()));
if ( ASSETCHAINS_SYMBOL[0] != 0 )
{
ret.push_back(Pair("MoMoM",MoMoM.GetHex()));
ret.push_back(Pair("MoMoMoffset",MoMoMoffset));
ret.push_back(Pair("MoMoMdepth",MoMoMdepth));
ret.push_back(Pair("kmdstarti",kmdstarti));
ret.push_back(Pair("kmdendi",kmdendi));
}
} else ret.push_back(Pair("error",(char *)"no MoM for height"));
return ret;
}
UniValue MoMoMdata(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() != 3 )
throw runtime_error("MoMoMdata symbol kmdheight ccid\n");
UniValue ret(UniValue::VOBJ);
char* symbol = (char *)params[0].get_str().c_str();
int kmdheight = atoi(params[1].get_str().c_str());
int ccid = atoi(params[2].get_str().c_str());
ret.push_back(Pair("coin",symbol));
ret.push_back(Pair("kmdheight",kmdheight));
ret.push_back(Pair("ccid", ccid));
uint256 destNotarisationTxid;
std::vector<uint256> moms;
uint256 MoMoM = CalculateProofRoot(symbol, ccid, kmdheight, moms, destNotarisationTxid);
UniValue valMoms(UniValue::VARR);
for (int i=0; i<moms.size(); i++) valMoms.push_back(moms[i].GetHex());
ret.push_back(Pair("MoMs", valMoms));
ret.push_back(Pair("notarization_hash", destNotarisationTxid.GetHex()));
ret.push_back(Pair("MoMoM", MoMoM.GetHex()));
auto vmomomdata = E_MARSHAL(ss << MoMoM; ss << ((uint32_t)0));
ret.push_back(Pair("data", HexStr(vmomomdata)));
return ret;
}
UniValue calc_MoM(const UniValue& params, bool fHelp)
{
int32_t height,MoMdepth; uint256 MoM; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR);
if ( fHelp || params.size() != 2 )
throw runtime_error("calc_MoM height MoMdepth\n");
LOCK(cs_main);
height = atoi(params[0].get_str().c_str());
MoMdepth = atoi(params[1].get_str().c_str());
if ( height <= 0 || MoMdepth <= 0 || MoMdepth >= height )
throw runtime_error("calc_MoM illegal height or MoMdepth\n");
//fprintf(stderr,"height_MoM height.%d\n",height);
MoM = komodo_calcMoM(height,MoMdepth);
ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)));
ret.push_back(Pair("height",height));
ret.push_back(Pair("MoMdepth",MoMdepth));
ret.push_back(Pair("MoM",MoM.GetHex()));
return ret;
}

View File

@@ -302,15 +302,17 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "paxpending", &paxpending, true }, { "blockchain", "paxpending", &paxpending, true },
{ "blockchain", "paxprices", &paxprices, true }, { "blockchain", "paxprices", &paxprices, true },
{ "blockchain", "notaries", &notaries, true }, { "blockchain", "notaries", &notaries, true },
{ "blockchain", "allMoMs", &allMoMs, true },
{ "blockchain", "MoMoMdata", &MoMoMdata, true },
{ "blockchain", "calc_MoM", &calc_MoM, true },
{ "blockchain", "height_MoM", &height_MoM, true },
{ "blockchain", "txMoMproof", &txMoMproof, true },
{ "blockchain", "minerids", &minerids, true }, { "blockchain", "minerids", &minerids, true },
{ "blockchain", "kvsearch", &kvsearch, true }, { "blockchain", "kvsearch", &kvsearch, true },
{ "blockchain", "kvupdate", &kvupdate, true }, { "blockchain", "kvupdate", &kvupdate, true },
/* Cross chain utilities */
{ "crosschain", "MoMoMdata", &MoMoMdata, true },
{ "crosschain", "calc_MoM", &calc_MoM, true },
{ "crosschain", "height_MoM", &height_MoM, true },
{ "crosschain", "assetchainproof", &assetchainproof, true },
{ "crosschain", "crosschainproof", &crosschainproof, true },
/* Mining */ /* Mining */
{ "mining", "getblocktemplate", &getblocktemplate, true }, { "mining", "getblocktemplate", &getblocktemplate, true },
{ "mining", "getmininginfo", &getmininginfo, true }, { "mining", "getmininginfo", &getmininginfo, true },

View File

@@ -312,11 +312,11 @@ extern UniValue z_validateaddress(const UniValue& params, bool fHelp); // in rpc
extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp
extern UniValue z_validatepaymentdisclosure(const UniValue &params, bool fHelp); // in rpcdisclosure.cpp extern UniValue z_validatepaymentdisclosure(const UniValue &params, bool fHelp); // in rpcdisclosure.cpp
extern UniValue allMoMs(const UniValue& params, bool fHelp);
extern UniValue MoMoMdata(const UniValue& params, bool fHelp); extern UniValue MoMoMdata(const UniValue& params, bool fHelp);
extern UniValue calc_MoM(const UniValue& params, bool fHelp); extern UniValue calc_MoM(const UniValue& params, bool fHelp);
extern UniValue height_MoM(const UniValue& params, bool fHelp); extern UniValue height_MoM(const UniValue& params, bool fHelp);
extern UniValue txMoMproof(const UniValue& params, bool fHelp); extern UniValue assetchainproof(const UniValue& params, bool fHelp);
extern UniValue crosschainproof(const UniValue& params, bool fHelp);
extern UniValue notaries(const UniValue& params, bool fHelp); extern UniValue notaries(const UniValue& params, bool fHelp);
extern UniValue minerids(const UniValue& params, bool fHelp); extern UniValue minerids(const UniValue& params, bool fHelp);
extern UniValue kvsearch(const UniValue& params, bool fHelp); extern UniValue kvsearch(const UniValue& params, bool fHelp);

View File

@@ -28,7 +28,7 @@ class TestCoinImport : public ::testing::Test, public Eval {
public: public:
CMutableTransaction burnTx; CMutableTransaction burnTx;
std::vector<CTxOut> payouts; std::vector<CTxOut> payouts;
MomoProof proof; TxProof proof;
uint256 MoMoM; uint256 MoMoM;
CMutableTransaction importTx; CMutableTransaction importTx;
uint32_t chainId = 2; uint32_t chainId = 2;

View File

@@ -28,7 +28,6 @@
extern uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth); extern uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
extern struct notarized_checkpoint *komodo_npptr_at(int idx);
/* /*
@@ -109,8 +108,6 @@ TEST_F(TestCrossChain, testCreateAndValidateImportProof)
mtx.vin[0].scriptSig << getSig(mtx, inputTx.vout[0].scriptPubKey); mtx.vin[0].scriptSig << getSig(mtx, inputTx.vout[0].scriptPubKey);
acceptTxFail(CTransaction(mtx)); acceptTxFail(CTransaction(mtx));
printf("accept %snotarisation: %s\n", data.IsBackNotarisation ? "back" : "",
mtx.GetHash().GetHex().data());
return mtx.GetHash(); return mtx.GetHash();
}; };
@@ -139,34 +136,13 @@ TEST_F(TestCrossChain, testCreateAndValidateImportProof)
* Generate proof * Generate proof
*/ */
uint256 txid = blocks[7].vtx[0].GetHash(); uint256 txid = blocks[7].vtx[0].GetHash();
int npIdx; TxProof proof = GetAssetchainProof(txid);
std::pair<uint256,MerkleBranch> proof = GetAssetchainProof(txid, npIdx);
SendIPC(E_MARSHAL(ss << txid; ss << proof)); SendIPC(E_MARSHAL(ss << txid; ss << proof));
E_UNMARSHAL(RecvIPC(), ss >> proof);
/* std::pair<uint256,NotarisationData> bn;
* Test proof if (!GetNextBacknotarisation(proof.first, bn)) return 1;
*/ return proof.second.Exec(txid) == bn.second.MoMoM ? 0 : 1;
std::pair<uint256,MerkleBranch> ccProof;
E_UNMARSHAL(RecvIPC(), ss >> ccProof);
// Now we have the branch with the hash of the notarisation on KMD
// What we'd like is the notarised height on PIZZA so we can go forward
// to the next backnotarisation, and then to the next, to get the M3.
uint256 result = ccProof.second.Exec(txid);
printf("result m3: %s\n", result.GetHex().data());
struct notarized_checkpoint* np = komodo_npptr_at(npIdx+1);
std::pair<uint256,NotarisationData> b;
pnotarisations->Read(np->notarized_desttxid, b);
printf("m3@1: %s\n", b.second.MoMoM.GetHex().data());
{
printf("RunTestAssetChain.test {\n txid: %s\n momom: %s\n", txid.GetHex().data(), b.second.MoMoM.GetHex().data());
printf(" idx: %i\n", ccProof.second.nIndex);
for (int i=0; i<ccProof.second.branch.size(); i++) printf(" %s", ccProof.second.branch[i].GetHex().data());
printf("\n}\n");
}
return b.second.MoMoM == result ? 0 : 1;
}; };
auto RunTestKmd = [&] () auto RunTestKmd = [&] ()
@@ -186,10 +162,9 @@ TEST_F(TestCrossChain, testCreateAndValidateImportProof)
n.txHash = RecordNotarisation(blocks[height].vtx[0], n); n.txHash = RecordNotarisation(blocks[height].vtx[0], n);
{ {
std::vector<uint256> moms; std::vector<uint256> moms;
int assetChainHeight; uint256 destNotarisationTxid;
n.MoMoM = GetProofRoot(n.symbol, 2, height, moms, &assetChainHeight); n.MoMoM = CalculateProofRoot(n.symbol, 2, height, moms, destNotarisationTxid);
} }
printf("RunTestKmd {\n kmdnotid:%s\n momom:%s\n}\n", n.txHash.GetHex().data(), n.MoMoM.GetHex().data());
n.IsBackNotarisation = 1; n.IsBackNotarisation = 1;
SendIPC(E_MARSHAL(ss << n)); SendIPC(E_MARSHAL(ss << n));
} }
@@ -197,11 +172,11 @@ TEST_F(TestCrossChain, testCreateAndValidateImportProof)
/* /*
* Extend proof * Extend proof
*/ */
std::pair<uint256,MerkleBranch> proof; TxProof proof;
uint256 txid; uint256 txid;
// Extend proof to MoMoM // Extend proof to MoMoM
assert(E_UNMARSHAL(RecvIPC(), ss >> txid; ss >> proof)); assert(E_UNMARSHAL(RecvIPC(), ss >> txid; ss >> proof));
proof.second = GetCrossChainProof(txid, (char*)"PIZZA", 2, proof.first, proof.second); proof = GetCrossChainProof(txid, (char*)"PIZZA", 2, proof);
SendIPC(E_MARSHAL(ss << proof)); SendIPC(E_MARSHAL(ss << proof));
}; };
@@ -217,20 +192,12 @@ TEST_F(TestCrossChain, testCreateAndValidateImportProof)
else { else {
assert(0 == zmq_bind(socket, endpoint)); assert(0 == zmq_bind(socket, endpoint));
RunTestKmd(); RunTestKmd();
int returnStatus; int returnStatus;
waitpid(childPid, &returnStatus, 0); waitpid(childPid, &returnStatus, 0);
unlink("tmpKomodoTestCrossChainSock"); unlink("tmpKomodoTestCrossChainSock");
ASSERT_EQ(0, returnStatus); ASSERT_EQ(0, returnStatus);
} }
/*
* We can now prove a tx from A on A, via a merkle root backpropagated from KMD.
*
* The transaction that we'll try to prove is the coinbase from the 3rd block.
* We should be able to start with only that transaction ID, and generate a merkle
* proof.
*/
} }

View File

@@ -72,13 +72,9 @@ void generateBlock(CBlock *block)
SetMockTime(nMockTime+=100); // CreateNewBlock can fail if not enough time passes SetMockTime(nMockTime+=100); // CreateNewBlock can fail if not enough time passes
char symbolPrefix = ASSETCHAINS_SYMBOL[0];
//ASSETCHAINS_SYMBOL[0] = 0; // generate block fails otherwise
try { try {
UniValue out = generate(params, false); UniValue out = generate(params, false);
blockId.SetHex(out[0].getValStr()); blockId.SetHex(out[0].getValStr());
ASSETCHAINS_SYMBOL[0] = symbolPrefix;
if (block) ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId], false)); if (block) ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId], false));
} catch (const UniValue& e) { } catch (const UniValue& e) {
FAIL() << "failed to create block: " << e.write().data(); FAIL() << "failed to create block: " << e.write().data();