Browse Source

wip

pull/4/head
Scott Sadler 6 years ago
parent
commit
20c3ac51c2
  1. 1
      .gitignore
  2. 5
      src/Makefile.am
  3. 3
      src/Makefile.ktest.include
  4. 3
      src/cc/betprotocol.cpp
  5. 48
      src/cc/eval.cpp
  6. 105
      src/cc/eval.h
  7. 70
      src/cc/import.cpp
  8. 0
      src/cc/utils.cpp
  9. 34
      src/cc/utils.h
  10. 2
      src/coins.cpp
  11. 217
      src/crosschain.cpp
  12. 21
      src/crosschain.h
  13. 68
      src/importcoin.cpp
  14. 6
      src/importcoin.h
  15. 4
      src/init.cpp
  16. 12
      src/main.cpp
  17. 2
      src/miner.cpp
  18. 46
      src/notarisationdb.cpp
  19. 26
      src/notarisationdb.h
  20. 30
      src/primitives/block.cpp
  21. 4
      src/primitives/block.h
  22. 93
      src/rpcblockchain.cpp
  23. 3
      src/script/cc.h
  24. 1
      src/test-komodo/main.cpp
  25. 4
      src/test-komodo/test_coinimport.cpp
  26. 267
      src/test-komodo/test_crosschain.cpp
  27. 25
      src/test-komodo/testutils.cpp
  28. 2
      src/test-komodo/testutils.h

1
.gitignore

@ -120,3 +120,4 @@ src/komodo-cli
src/komodod
src/komodo-tx
src/komodo-test
src/wallet-utility

5
src/Makefile.am

@ -256,10 +256,11 @@ libbitcoin_server_a_SOURCES = \
asyncrpcqueue.cpp \
bloom.cpp \
cc/eval.cpp \
cc/importcoin.cpp \
cc/import.cpp \
cc/betprotocol.cpp \
chain.cpp \
checkpoints.cpp \
crosschain.cpp \
deprecation.cpp \
httprpc.cpp \
httpserver.cpp \
@ -271,6 +272,7 @@ libbitcoin_server_a_SOURCES = \
miner.cpp \
net.cpp \
noui.cpp \
notarisationdb.cpp \
paymentdisclosure.cpp \
paymentdisclosuredb.cpp \
policy/fees.cpp \
@ -384,6 +386,7 @@ libbitcoin_common_a_SOURCES = \
core_read.cpp \
core_write.cpp \
hash.cpp \
importcoin.cpp \
key.cpp \
keystore.cpp \
netbase.cpp \

3
src/Makefile.ktest.include

@ -9,7 +9,8 @@ komodo_test_SOURCES = \
test-komodo/test_cryptoconditions.cpp \
test-komodo/test_coinimport.cpp \
test-komodo/test_eval_bet.cpp \
test-komodo/test_eval_notarisation.cpp
test-komodo/test_eval_notarisation.cpp \
test-komodo/test_crosschain.cpp
komodo_test_CPPFLAGS = $(komodod_CPPFLAGS)

3
src/cc/betprotocol.cpp

@ -5,8 +5,9 @@
#include "chain.h"
#include "streams.h"
#include "script/cc.h"
#include "cc/eval.h"
#include "cc/betprotocol.h"
#include "cc/eval.h"
#include "cc/utils.h"
#include "primitives/transaction.h"

48
src/cc/eval.cpp

@ -1,9 +1,11 @@
#include <assert.h>
#include <cryptoconditions.h>
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "script/cc.h"
#include "cc/eval.h"
#include "cc/utils.h"
#include "main.h"
#include "chain.h"
#include "core_io.h"
@ -14,9 +16,7 @@ Eval* EVAL_TEST = 0;
bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
{
Eval eval_;
Eval *eval = EVAL_TEST;
if (!eval) eval = &eval_;
EvalRef eval;
bool out = eval->Dispatch(cond, tx, nIn);
assert(eval->state.IsValid() == out);
@ -162,8 +162,7 @@ bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data)
CBlockIndex block;
if (!GetTxConfirmed(notaryHash, notarisationTx, block)) return false;
if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) return false;
if (notarisationTx.vout.size() < 2) return false;
if (!data.Parse(notarisationTx.vout[1].scriptPubKey)) return false;
if (!ParseNotarisationOpReturn(notarisationTx, data)) return false;
return true;
}
@ -176,34 +175,13 @@ bool Eval::GetNotarisationData(int notarisationHeight, NotarisationData &data, b
/*
* Notarisation data, ie, OP_RETURN payload in notarisation transactions
*/
extern char ASSETCHAINS_SYMBOL[16];
bool NotarisationData::Parse(const CScript scriptPK)
bool ParseNotarisationOpReturn(const CTransaction &tx, NotarisationData &data)
{
*this = NotarisationData();
if (tx.vout.size() < 2) return false;
std::vector<unsigned char> vdata;
if (!GetOpReturnData(scriptPK, vdata)) return false;
CDataStream ss(vdata, SER_NETWORK, PROTOCOL_VERSION);
try {
ss >> blockHash;
ss >> height;
if (ASSETCHAINS_SYMBOL[0])
ss >> txHash;
char *nullPos = (char*) memchr(&ss[0], 0, ss.size());
if (!nullPos) return false;
ss.read(symbol, nullPos-&ss[0]+1);
if (ss.size() < 36) return false;
ss >> MoM;
ss >> MoMDepth;
} catch (...) {
return false;
}
return true;
if (!GetOpReturnData(tx.vout[1].scriptPubKey, vdata)) return false;
bool out = E_UNMARSHAL(vdata, ss >> data);
return out;
}
@ -240,3 +218,11 @@ uint256 SafeCheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleB
}
return hash;
}
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves)
{
bool fMutated;
std::vector<uint256> vMerkleTree;
return BuildMerkleTree(&fMutated, vLeaves, vMerkleTree);
}

105
src/cc/eval.h

@ -3,6 +3,7 @@
#include <cryptoconditions.h>
#include "cc/utils.h"
#include "chain.h"
#include "streams.h"
#include "version.h"
@ -78,6 +79,23 @@ public:
};
extern Eval* EVAL_TEST;
/*
* Get a pointer to an Eval to use
*/
typedef std::unique_ptr<Eval,void(*)(Eval*)> EvalRef_;
class EvalRef : public EvalRef_
{
public:
EvalRef() : EvalRef_(
EVAL_TEST ? EVAL_TEST : new Eval(),
[](Eval* e){if (e!=EVAL_TEST) delete e;}) { }
};
bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn);
@ -97,24 +115,68 @@ public:
evaluate(std::vector<unsigned char> header, std::vector<unsigned char> body) = 0;
};
extern char ASSETCHAINS_SYMBOL[65];
/*
* Data from notarisation OP_RETURN
* Data from notarisation OP_RETURN from chain being notarised
*/
class NotarisationData {
class NotarisationData
{
public:
bool IsBackNotarisation = 0;
uint256 blockHash;
uint32_t height;
uint256 txHash; // Only get this guy in asset chains not in KMD
char symbol[64];
char symbol[64] = "\0";
uint256 MoM;
uint32_t MoMDepth;
uint32_t ccId;
uint256 MoMoM;
uint32_t MoMoMDepth;
bool Parse(CScript scriptPubKey);
NotarisationData(bool IsBack=0) : IsBackNotarisation(IsBack) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(blockHash);
READWRITE(height);
if (IsBackNotarisation || (!ser_action.ForRead() && !txHash.IsNull()))
READWRITE(txHash);
SerSymbol(s, ser_action);
READWRITE(MoM);
READWRITE(MoMDepth);
if (s.size() == 0) return;
READWRITE(ccId);
if (IsBackNotarisation) {
READWRITE(MoMoM);
READWRITE(MoMoMDepth);
}
}
template <typename Stream>
void SerSymbol(Stream& s, CSerActionSerialize act)
{
s.write(symbol, strlen(symbol)+1);
}
template <typename Stream>
void SerSymbol(Stream& s, CSerActionUnserialize act)
{
char *nullPos = (char*) memchr(&s[0], 0, s.size());
if (!nullPos)
throw std::ios_base::failure("couldn't parse symbol");
s.read(symbol, nullPos-&s[0]+1);
}
};
bool ParseNotarisationOpReturn(const CTransaction &tx, NotarisationData &data);
/*
* Eval code utilities.
*/
@ -126,31 +188,6 @@ FOREACH_EVAL(EVAL_GENERATE_DEF);
std::string EvalToStr(EvalCode c);
/*
* Serialisation boilerplate
*/
#define E_MARSHAL(body) SerializeF([&] (CDataStream &ss) {body;})
template <class T>
std::vector<uint8_t> SerializeF(const T f)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
f(ss);
return std::vector<unsigned char>(ss.begin(), ss.end());
}
#define E_UNMARSHAL(params, body) DeserializeF(params, [&] (CDataStream &ss) {body;})
template <class T>
bool DeserializeF(const std::vector<unsigned char> vIn, T f)
{
CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION);
try {
f(ss);
if (ss.eof()) return true;
} catch(...) {}
return false;
}
/*
* Merkle stuff
*/
@ -167,6 +204,13 @@ public:
MerkleBranch(int i, std::vector<uint256> b) : nIndex(i), branch(b) {}
uint256 Exec(uint256 hash) const { return SafeCheckMerkleBranch(hash, branch, nIndex); }
MerkleBranch& operator<<(MerkleBranch append)
{
nIndex += append.nIndex << branch.size();
branch.insert(branch.end(), append.branch.begin(), append.branch.end());
return *this;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@ -177,4 +221,7 @@ public:
};
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves);
#endif /* CC_EVAL_H */

70
src/cc/import.cpp

@ -0,0 +1,70 @@
#include "cc/eval.h"
#include "cc/utils.h"
#include "importcoin.h"
#include "primitives/transaction.h"
/*
* 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.
*/
bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
{
if (importTx.vout.size() == 0) return Invalid("no-vouts");
// params
MomoProof proof;
CTransaction burnTx;
if (!E_UNMARSHAL(params, ss >> proof; ss >> burnTx))
return Invalid("invalid-params");
// Control all aspects of this transaction
// It must not be at all malleable
if (MakeImportCoinTransaction(proof, burnTx, importTx.vout).GetHash() != importTx.GetHash())
return Invalid("non-canonical");
// burn params
uint32_t chain; // todo
uint256 payoutsHash;
std::vector<uint8_t> burnOpret;
if (burnTx.vout.size() == 0) return Invalid("invalid-burn-outputs");
GetOpReturnData(burnTx.vout[0].scriptPubKey, burnOpret);
if (!E_UNMARSHAL(burnOpret, ss >> VARINT(chain); ss >> payoutsHash))
return Invalid("invalid-burn-params");
// check chain
if (chain != GetCurrentLedgerID())
return Invalid("importcoin-wrong-chain");
// check burn amount
{
uint64_t burnAmount = burnTx.vout[0].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)
return Invalid("payout-too-high");
}
// Check burntx shows correct outputs hash
if (payoutsHash != SerializeHash(importTx.vout))
return Invalid("wrong-payouts");
// Check proof confirms existance of burnTx
{
NotarisationData data;
if (!GetNotarisationData(proof.notarisationHeight, data, true))
return Invalid("coudnt-load-momom");
if (data.MoMoM != proof.branch.Exec(burnTx.GetHash()))
return Invalid("momom-check-fail");
}
return Valid();
}

0
src/cc/utils.cpp

34
src/cc/utils.h

@ -0,0 +1,34 @@
#ifndef CC_UTILS_H
#define CC_UTILS_H
#include "streams.h"
#include "version.h"
/*
* Serialisation boilerplate
*/
template <class T>
std::vector<uint8_t> SerializeF(const T f)
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
f(ss);
return std::vector<unsigned char>(ss.begin(), ss.end());
}
template <class T>
bool DeserializeF(const std::vector<unsigned char> vIn, T f)
{
CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION);
try {
f(ss);
if (ss.eof()) return true;
} catch(...) {}
return false;
}
#define E_MARSHAL(body) SerializeF([&] (CDataStream &ss) {body;})
#define E_UNMARSHAL(params, body) DeserializeF(params, [&] (CDataStream &ss) {body;})
#endif /* CC_UTILS_H */

2
src/coins.cpp

@ -9,7 +9,7 @@
#include "version.h"
#include "policy/fees.h"
#include "komodo_defs.h"
#include "cc/importcoin.h"
#include "importcoin.h"
#include <assert.h>

217
src/crosschain.cpp

@ -0,0 +1,217 @@
#include "cc/eval.h"
#include "main.h"
#include "notarisationdb.h"
/* On KMD */
uint256 GetProofRoot(char* symbol, uint32_t targetCCid, int kmdHeight, std::vector<uint256> &moms, int* assetChainHeight)
{
/*
* 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
* including the block height of the last notarisation until the height before the
* previous notarisation.
*/
if (targetCCid <= 1)
return uint256();
int seenOwnNotarisations = 0;
// TODO: test height out of range
// TODO: Make sure that boundary for moms is notarisation tx not block
for (int i=0; i<1440; i++) {
if (i > kmdHeight) break;
NotarisationsInBlock notarisations;
uint256 blockHash = *chainActive[kmdHeight-i]->phashBlock;
if (!pnotarisations->Read(blockHash, notarisations))
continue;
BOOST_FOREACH(Notarisation& nota, notarisations) {
NotarisationData& data = nota.second;
if (data.ccId != targetCCid)
continue;
if (strcmp(data.symbol, symbol) == 0)
{
seenOwnNotarisations++;
if (seenOwnNotarisations == 2)
goto end;
if (seenOwnNotarisations == 1)
*assetChainHeight = data.height; // TODO: Needed?
continue; // Don't include own MoMs
}
if (seenOwnNotarisations == 1)
moms.push_back(data.MoM);
}
}
end:
return GetMerkleRoot(moms);
}
/* On KMD */
std::pair<uint256,MerkleBranch> GetCrossChainProof(uint256 txid, char* targetSymbol,
uint32_t targetCCid, uint256 notarisationTxid, MerkleBranch assetChainProof)
{
/*
* Here we are given a proof generated by an assetchain A which goes from given txid to
* an assetchain MoM. We need to go from the notarisationTxid for A to the MoMoM range of the
* backnotarisation for B (given by kmdheight of notarisation), find the MoM within the MoMs for
* that range, and finally extend the proof to lead to the MoMoM (proof root).
*/
EvalRef eval;
uint256 MoM = assetChainProof.Exec(txid);
// Get a kmd height for given notarisation Txid
int kmdHeight;
{
CTransaction sourceNotarisation;
uint256 hashBlock;
CBlockIndex blockIdx;
if (eval->GetTxConfirmed(notarisationTxid, sourceNotarisation, blockIdx))
kmdHeight = blockIdx.nHeight;
else if (eval->GetTxUnconfirmed(notarisationTxid, sourceNotarisation, hashBlock))
kmdHeight = chainActive.Tip()->nHeight;
else
throw std::runtime_error("Notarisation not found");
}
// Get MoMs for kmd height and symbol
std::vector<uint256> moms;
int targetChainStartHeight;
uint256 MoMoM = GetProofRoot(targetSymbol, targetCCid, kmdHeight, moms, &targetChainStartHeight);
if (MoMoM.IsNull())
throw std::runtime_error("No MoMs found");
// Find index of source MoM in MoMoM
int nIndex;
for (nIndex=0; nIndex<moms.size(); nIndex++)
if (moms[nIndex] == MoM)
goto cont;
throw std::runtime_error("Couldn't find MoM within MoMoM set");
cont:
// Create a branch
std::vector<uint256> newBranch;
{
CBlock fakeBlock;
for (int i=0; i<moms.size(); i++) {
CTransaction fakeTx;
// first value in CTransaction memory is it's hash
memcpy((void*)&fakeTx, moms[i].begin(), 32);
fakeBlock.vtx.push_back(fakeTx);
}
newBranch = fakeBlock.GetMerkleBranch(nIndex);
}
// Concatenate branches
MerkleBranch newProof = assetChainProof;
newProof << MerkleBranch(nIndex, newBranch);
// Check proof
if (newProof.Exec(txid) != MoMoM)
throw std::runtime_error("Proof check failed");
return std::make_pair(uint256(), newProof);
}
/* On assetchain */
bool ValidateCrossChainProof(uint256 txid, int notarisationHeight, MerkleBranch proof)
{
/*
* Here we are given a notarisation txid, and a proof.
* We go from the notarisation to get the backnotarisation, and verify the proof
* against the MoMoM it contains.
*/
}
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);
/*
* On assetchain
* in: txid
* out: pair<notarisationTxHash,merkleBranch>
*/
std::pair<uint256,MerkleBranch> GetAssetchainProof(uint256 hash)
{
uint256 notarisationHash, MoM,MoMoM; int32_t notarisedHeight, depth; CBlockIndex* blockIndex;
std::vector<uint256> branch;
int nIndex,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi;
{
uint256 blockHash;
CTransaction tx;
if (!GetTransaction(hash, tx, blockHash, true))
throw std::runtime_error("cannot find transaction");
blockIndex = mapBlockIndex[blockHash];
depth = komodo_MoM(&notarisedHeight, &MoM, &notarisationHash, blockIndex->nHeight,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi);
if (!depth)
throw std::runtime_error("notarisation not found");
// index of block in MoM leaves
nIndex = notarisedHeight - blockIndex->nHeight;
}
// build merkle chain from blocks to MoM
{
// since the merkle branch code is tied up in a block class
// and we want to make a merkle branch for something that isnt transactions
CBlock fakeBlock;
for (int i=0; i<depth; i++) {
uint256 mRoot = chainActive[notarisedHeight - i]->hashMerkleRoot;
CTransaction fakeTx;
// first value in CTransaction memory is it's hash
memcpy((void*)&fakeTx, mRoot.begin(), 32);
fakeBlock.vtx.push_back(fakeTx);
}
branch = fakeBlock.GetMerkleBranch(nIndex);
// Check branch
if (MoM != CBlock::CheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex))
throw std::runtime_error("Failed merkle block->MoM");
}
// Now get the tx merkle branch
{
CBlock block;
if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0)
throw std::runtime_error("Block not available (pruned data)");
if(!ReadBlockFromDisk(block, blockIndex,1))
throw std::runtime_error("Can't read block from disk");
// Locate the transaction in the block
int nTxIndex;
for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++)
if (block.vtx[nTxIndex].GetHash() == hash)
break;
if (nTxIndex == (int)block.vtx.size())
throw std::runtime_error("Error locating tx in block");
std::vector<uint256> txBranch = block.GetMerkleBranch(nTxIndex);
// Check branch
if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex))
throw std::runtime_error("Failed merkle tx->block");
// concatenate branches
nIndex = (nIndex << txBranch.size()) + nTxIndex;
branch.insert(branch.begin(), txBranch.begin(), txBranch.end());
}
// Check the proof
if (MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex))
throw std::runtime_error("Failed validating MoM");
// All done!
CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION);
return std::make_pair(notarisationHash, MerkleBranch(nIndex, branch));
}

21
src/crosschain.h

@ -0,0 +1,21 @@
#ifndef CROSSCHAIN_H
#define CROSSCHAIN_H
#include "cc/eval.h"
/* On assetchain */
std::pair<uint256,MerkleBranch> GetAssetchainProof(uint256 hash);
/* On KMD */
uint256 GetProofRoot(char* symbol, uint32_t targetCCid, int kmdHeight, std::vector<uint256> &moms, int* assetChainHeight);
/* On KMD */
std::pair<uint256,MerkleBranch> GetCrossChainProof(uint256 txid, char* targetSymbol,
uint32_t targetCCid, uint256 notarisationTxid, MerkleBranch assetChainProof);
/* On assetchain */
bool ValidateCrossChainProof(uint256 txid, int notarisationHeight, MerkleBranch proof);
#endif /* CROSSCHAIN_H */

68
src/cc/importcoin.cpp → src/importcoin.cpp

@ -1,4 +1,5 @@
#include "cc/importcoin.h"
#include "importcoin.h"
#include "cc/utils.h"
#include "coins.h"
#include "hash.h"
#include "script/cc.h"
@ -29,71 +30,6 @@ CTxOut MakeBurnOutput(CAmount value, int targetChain, const std::vector<CTxOut>
}
/*
* CC Eval method for import coin.
*
* This method has to control *every* parameter of the ImportCoin transaction, so that the legal
* importTx for a valid burnTx is 1:1. There can be no two legal importTx transactions for a burnTx
* on another chain.
*/
bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
{
if (importTx.vout.size() == 0) return Invalid("no-vouts");
// params
MomoProof proof;
CTransaction burnTx;
if (!E_UNMARSHAL(params, ss >> proof; ss >> burnTx))
return Invalid("invalid-params");
// Control all aspects of this transaction
// It must not be at all malleable
if (MakeImportCoinTransaction(proof, burnTx, importTx.vout).GetHash() != importTx.GetHash())
return Invalid("non-canonical");
// burn params
uint32_t chain; // todo
uint256 payoutsHash;
std::vector<uint8_t> burnOpret;
if (burnTx.vout.size() == 0) return Invalid("invalid-burn-outputs");
GetOpReturnData(burnTx.vout[0].scriptPubKey, burnOpret);
if (!E_UNMARSHAL(burnOpret, ss >> VARINT(chain); ss >> payoutsHash))
return Invalid("invalid-burn-params");
// check chain
if (chain != GetCurrentLedgerID())
return Invalid("importcoin-wrong-chain");
// check burn amount
{
uint64_t burnAmount = burnTx.vout[0].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)
return Invalid("payout-too-high");
}
// Check burntx shows correct outputs hash
if (payoutsHash != SerializeHash(importTx.vout))
return Invalid("wrong-payouts");
// Check proof confirms existance of burnTx
{
NotarisationData data;
if (!GetNotarisationData(proof.notarisationHeight, data, true))
return Invalid("coudnt-load-momom");
if (data.MoMoM != proof.branch.Exec(burnTx.GetHash()))
return Invalid("momom-check-fail");
}
return Valid();
}
static bool UnmarshalImportTx(const CTransaction &importTx, MomoProof &proof, CTransaction &burnTx)
{
CScript scriptSig = importTx.vin[0].scriptSig;

6
src/cc/importcoin.h → src/importcoin.h

@ -1,5 +1,5 @@
#ifndef CC_IMPORTCOIN_H
#define CC_IMPORTCOIN_H
#ifndef IMPORTCOIN_H
#define IMPORTCOIN_H
#include "cc/eval.h"
#include "coins.h"
@ -36,4 +36,4 @@ void AddImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs, i
void RemoveImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs);
int ExistsImportTombstone(const CTransaction &importTx, const CCoinsViewCache &inputs);
#endif /* CC_IMPORTCOIN_H */
#endif /* IMPORTCOIN_H */

4
src/init.cpp

@ -21,6 +21,7 @@
#include "httpserver.h"
#include "httprpc.h"
#include "key.h"
#include "notarisationdb.h"
#include "main.h"
#include "metrics.h"
#include "miner.h"
@ -1413,11 +1414,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
delete pcoinsdbview;
delete pcoinscatcher;
delete pblocktree;
delete pnotarisations;
pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex, dbCompression, dbMaxOpenFiles);
pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex);
pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
pcoinsTip = new CCoinsViewCache(pcoinscatcher);
pnotarisations = new NotarisationDB(100*1024*1024, false, fReindex);
if (fReindex) {
pblocktree->WriteReindexing(true);

12
src/main.cpp

@ -10,7 +10,7 @@
#include "addrman.h"
#include "alert.h"
#include "arith_uint256.h"
#include "cc/importcoin.h"
#include "importcoin.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
@ -20,6 +20,7 @@
#include "init.h"
#include "merkleblock.h"
#include "metrics.h"
#include "notarisationdb.h"
#include "net.h"
#include "pow.h"
#include "script/interpreter.h"
@ -2598,6 +2599,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
}
}
static int64_t nTimeVerify = 0;
static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
@ -2833,6 +2835,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
// Record Notarisations
NotarisationsInBlock notarisations = GetNotarisationsInBlock(block, pindex->nHeight);
pnotarisations->Write(block.GetHash(), notarisations);
WriteBackNotarisations(notarisations); // Very important to disconnect this
// TODO: Disconnect?
view.PushAnchor(tree);
if (!fJustCheck) {

2
src/miner.cpp

@ -11,7 +11,7 @@
#include "amount.h"
#include "base58.h"
#include "chainparams.h"
#include "cc/importcoin.h"
#include "importcoin.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"

46
src/notarisationdb.cpp

@ -0,0 +1,46 @@
#include "leveldbwrapper.h"
#include "notarisationdb.h"
#include "uint256.h"
#include "cc/eval.h"
#include <boost/foreach.hpp>
NotarisationDB *pnotarisations;
NotarisationDB::NotarisationDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "notarisations", nCacheSize, fMemory, fWipe, false, 64) {
}
NotarisationsInBlock GetNotarisationsInBlock(const CBlock &block, int nHeight)
{
EvalRef eval;
NotarisationsInBlock vNotarisations;
bool IsBackNotarisation = ASSETCHAINS_SYMBOL[0] != 0;
for (unsigned int i = 0; i < block.vtx.size(); i++) {
CTransaction tx = block.vtx[i];
if (eval->CheckNotaryInputs(tx, nHeight, block.nTime)) {
NotarisationData data(IsBackNotarisation);
if (ParseNotarisationOpReturn(tx, data))
vNotarisations.push_back(std::make_pair(tx.GetHash(), data));
else
fprintf(stderr, "Warning: Couldn't parse notarisation for tx: %s at height %i\n",
tx.GetHash().GetHex().data(), nHeight);
}
}
return vNotarisations;
}
/*
* Write an index of KMD notarisation id -> backnotarisation
*/
void WriteBackNotarisations(NotarisationsInBlock notarisations)
{
BOOST_FOREACH(Notarisation &n, notarisations)
{
if (n.second.IsBackNotarisation)
pnotarisations->Write(n.second.txHash, n);
}
}

26
src/notarisationdb.h

@ -0,0 +1,26 @@
#ifndef NOTARISATIONDB_H
#define NOTARISATIONDB_H
#include "uint256.h"
#include "leveldbwrapper.h"
#include "cc/eval.h"
class NotarisationDB : public CLevelDBWrapper
{
public:
NotarisationDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
};
extern NotarisationDB *pnotarisations;
typedef std::pair<uint256,NotarisationData> Notarisation;
typedef std::vector<Notarisation> NotarisationsInBlock;
NotarisationsInBlock GetNotarisationsInBlock(const CBlock &block, int nHeight);
void WriteBackNotarisations(NotarisationsInBlock notarisations);
#endif /* NOTARISATIONDB_H */

30
src/primitives/block.cpp

@ -15,7 +15,9 @@ uint256 CBlockHeader::GetHash() const
return SerializeHash(*this);
}
uint256 CBlock::BuildMerkleTree(bool* fMutated) const
uint256 BuildMerkleTree(bool* fMutated, const std::vector<uint256> leaves,
std::vector<uint256> &vMerkleTree)
{
/* WARNING! If you're reading this because you're learning about crypto
and/or designing a new system that will use merkle trees, keep in mind
@ -28,10 +30,10 @@ uint256 CBlock::BuildMerkleTree(bool* fMutated) const
transactions leading to the same merkle root. For example, these two
trees:
A A
/ \ / \
B C B C
/ \ | / \ / \
A A
/ \ / \
B C B C
/ \ \ / \ / \
D E F D E F F
/ \ / \ / \ / \ / \ / \ / \
1 2 3 4 5 6 1 2 3 4 5 6 5 6
@ -52,13 +54,14 @@ uint256 CBlock::BuildMerkleTree(bool* fMutated) const
known ways of changing the transactions without affecting the merkle
root.
*/
vMerkleTree.clear();
vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes.
for (std::vector<CTransaction>::const_iterator it(vtx.begin()); it != vtx.end(); ++it)
vMerkleTree.push_back(it->GetHash());
vMerkleTree.reserve(leaves.size() * 2 + 16); // Safe upper bound for the number of total nodes.
for (std::vector<uint256>::const_iterator it(leaves.begin()); it != leaves.end(); ++it)
vMerkleTree.push_back(*it);
int j = 0;
bool mutated = false;
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
for (int nSize = leaves.size(); nSize > 1; nSize = (nSize + 1) / 2)
{
for (int i = 0; i < nSize; i += 2)
{
@ -78,6 +81,15 @@ uint256 CBlock::BuildMerkleTree(bool* fMutated) const
return (vMerkleTree.empty() ? uint256() : vMerkleTree.back());
}
uint256 CBlock::BuildMerkleTree(bool* fMutated) const
{
std::vector<uint256> leaves;
for (int i=0; i<vtx.size(); i++) leaves.push_back(vtx[i].GetHash());
return ::BuildMerkleTree(fMutated, leaves, vMerkleTree);
}
std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())

4
src/primitives/block.h

@ -139,6 +139,10 @@ public:
};
uint256 BuildMerkleTree(bool* fMutated, const std::vector<uint256> leaves,
std::vector<uint256> &vMerkleTree);
/**
* Custom serializer for CBlockHeader that omits the nonce and solution, for use
* as input to Equihash.

93
src/rpcblockchain.cpp

@ -7,6 +7,7 @@
#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
#include "crosschain.h"
#include "base58.h"
#include "consensus/validation.h"
#include "cc/eval.h"
@ -934,87 +935,35 @@ UniValue txMoMproof(const UniValue& params, bool fHelp)
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());
uint256 blockHash;
CTransaction tx;
if (!GetTransaction(hash, tx, blockHash, true))
throw runtime_error("cannot find transaction");
blockIndex = mapBlockIndex[blockHash];
depth = komodo_MoM(&notarisedHeight, &MoM, &notarisationHash, blockIndex->nHeight,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi);
if (!depth)
throw runtime_error("notarisation not found");
// index of block in MoM leaves
nIndex = notarisedHeight - blockIndex->nHeight;
}
// build merkle chain from blocks to MoM
{
// since the merkle branch code is tied up in a block class
// and we want to make a merkle branch for something that isnt transactions
CBlock fakeBlock;
for (int i=0; i<depth; i++) {
uint256 mRoot = chainActive[notarisedHeight - i]->hashMerkleRoot;
CTransaction fakeTx;
// first value in CTransaction memory is it's hash
memcpy((void*)&fakeTx, mRoot.begin(), 32);
fakeBlock.vtx.push_back(fakeTx);
}
branch = fakeBlock.GetMerkleBranch(nIndex);
if ( fHelp || params.size() != 1)
throw runtime_error("txMoMproof needs a txid");
// Check branch
if (MoM != CBlock::CheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed merkle block->MoM");
}
hash = uint256S(params[0].get_str());
// Now get the tx merkle branch
{
CBlock block;
if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
if(!ReadBlockFromDisk(block, blockIndex,1))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
// Locate the transaction in the block
int nTxIndex;
for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++)
if (block.vtx[nTxIndex].GetHash() == hash)
break;
std::vector<uint8_t> proofData = E_MARSHAL(ss << GetAssetchainProof(hash));
return HexStr(proofData);
}
if (nTxIndex == (int)block.vtx.size())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Error locating tx in block");
std::vector<uint256> txBranch = block.GetMerkleBranch(nTxIndex);
UniValue getproofroot(const UniValue& params, bool fHelp)
{
std::string symbol;
int kmdHeight;
// Check branch
if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed merkle tx->block");
// concatenate branches
nIndex = (nIndex << txBranch.size()) + nTxIndex;
branch.insert(branch.begin(), txBranch.begin(), txBranch.end());
}
// Check the proof
if (MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed validating MoM");
// 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");
// Encode and return
CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION);
ssProof << std::make_pair(notarisationHash, MerkleBranch(nIndex, branch));
return HexStr(ssProof.begin(), ssProof.end());
UniValue ret(UniValue::VOBJ);
return ret;
}
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];

3
src/script/cc.h

@ -1,6 +1,8 @@
#ifndef SCRIPT_CC_H
#define SCRIPT_CC_H
#include <memory>
#include "pubkey.h"
#include "script/script.h"
#include "cryptoconditions/include/cryptoconditions.h"
@ -79,5 +81,4 @@ bool GetPushData(const CScript &sig, std::vector<unsigned char> &data);
*/
bool GetOpReturnData(const CScript &sig, std::vector<unsigned char> &data);
#endif /* SCRIPT_CC_H */

1
src/test-komodo/main.cpp

@ -9,6 +9,7 @@
int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
ECC_Start();
ECCVerifyHandle handle; // Inits secp256k1 verify context
SelectParams(CBaseChainParams::REGTEST);
CBitcoinSecret vchSecret;

4
src/test-komodo/test_coinimport.cpp

@ -2,14 +2,14 @@
#include <cryptoconditions.h>
#include <gtest/gtest.h>
#include "cc/importcoin.h"
#include "cc/eval.h"
#include "importcoin.h"
#include "base58.h"
#include "core_io.h"
#include "key.h"
#include "main.h"
#include "script/cc.h"
#include "primitives/transaction.h"
#include "script/cc.h"
#include "script/interpreter.h"
#include "script/serverchecker.h"
#include "txmempool.h"

267
src/test-komodo/test_crosschain.cpp

@ -0,0 +1,267 @@
#include <zmq.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <cryptoconditions.h>
#include <gtest/gtest.h>
#include "cc/eval.h"
#include "importcoin.h"
#include "base58.h"
#include "core_io.h"
#include "crosschain.h"
#include "key.h"
#include "main.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "script/cc.h"
#include "script/interpreter.h"
#include "script/serverchecker.h"
#include "txmempool.h"
#include "crosschain.h"
#include "testutils.h"
extern uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth);
/*
* Tests for the whole process of creating and validating notary proofs
* using proof roots (MoMoMs). This is to support coin imports.
*/
namespace TestCrossChainProof {
class TestCrossChain : public ::testing::Test, public Eval {
public:
bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const
{
NotarisationData data;
return ParseNotarisationOpReturn(tx, data);
}
protected:
static void SetUpTestCase() { }
virtual void SetUp() {
ASSETCHAINS_CC = 1;
EVAL_TEST = this;
}
};
TEST_F(TestCrossChain, testCreateAndValidateImportProof)
{
/*
* This tests the full process of creation of a cross chain proof.
* For the purposes of the test we will use one assetchain and a KMD chain.
*
* In order to do this test, we need 2 blockchains, so we'll fork and make a socket
* for IPC.
*/
int childPid = fork();
void *ctx = zmq_ctx_new();
void *socket = zmq_socket(ctx, ZMQ_PAIR);
setupChain();
std::vector<CBlock> blocks;
blocks.resize(10);
NotarisationData a2kmd, kmd2a(true);
auto SendIPC = [&] (std::vector<uint8_t> v) {
assert(v.size() == zmq_send(socket, v.data(), v.size(), 0));
};
auto RecvIPC = [&] () {
std::vector<uint8_t> out;
out.resize(100000);
int len = zmq_recv(socket, out.data(), out.size(), 0);
assert(len != -1);
out.resize(len);
return out;
};
auto RecordNotarisation = [&] (CTransaction inputTx, NotarisationData data) {
CMutableTransaction mtx = spendTx(inputTx);
mtx.vout.resize(2);
mtx.vout[0].scriptPubKey << VCH(notaryKey.GetPubKey().begin(), 33) << OP_CHECKSIG;
mtx.vout[1].scriptPubKey << OP_RETURN << E_MARSHAL(ss << data);
mtx.vout[1].nValue = 0;
mtx.vin[0].scriptSig << getSig(mtx, inputTx.vout[0].scriptPubKey);
acceptTxFail(CTransaction(mtx));
printf("accept %snotarisation: %s\n", data.IsBackNotarisation ? "back" : "",
mtx.GetHash().GetHex().data());
return mtx.GetHash();
};
auto RunTestAssetchain = [&] ()
{
NotarisationData back(1);
strcpy(ASSETCHAINS_SYMBOL, "symbolA");
strcpy(a2kmd.symbol, "symbolA");
a2kmd.ccId = 2;
/*
* Notarisation 1
*/
generateBlock(&blocks[1]);
generateBlock(&blocks[2]);
a2kmd.blockHash = blocks[2].GetHash();
a2kmd.MoM = komodo_calcMoM(a2kmd.height = chainActive.Height(), a2kmd.MoMDepth = 2);
SendIPC(E_MARSHAL(ss << a2kmd));
E_UNMARSHAL(RecvIPC(), ss >> back);
RecordNotarisation(blocks[1].vtx[0], back);
/*
* Notarisation 2
*/
generateBlock(&blocks[3]);
generateBlock(&blocks[4]);
a2kmd.blockHash = blocks[4].GetHash();
a2kmd.MoM = komodo_calcMoM(a2kmd.height = chainActive.Height(), a2kmd.MoMDepth = 2);
SendIPC(E_MARSHAL(ss << a2kmd));
E_UNMARSHAL(RecvIPC(), ss >> back);
RecordNotarisation(blocks[3].vtx[0], back);
/*
* Generate proof
*/
generateBlock(&blocks[5]);
uint256 txid = blocks[3].vtx[0].GetHash();
std::pair<uint256,MerkleBranch> assetChainProof = GetAssetchainProof(txid);
SendIPC(E_MARSHAL(ss << txid; ss << assetChainProof));
};
auto RunTestKmd = [&] ()
{
NotarisationData n;
/*
* Notarisation 1
*/
E_UNMARSHAL(RecvIPC(), ss >> n);
// Grab a coinbase input to fund notarisation
generateBlock(&blocks[1]);
n.txHash = RecordNotarisation(blocks[1].vtx[0], a2kmd);
n.height = chainActive.Height();
SendIPC(E_MARSHAL(ss << n));
/*
* Notarisation 2
*/
E_UNMARSHAL(RecvIPC(), ss >> n);
// Grab a coinbase input to fund notarisation
generateBlock(&blocks[2]);
n.txHash = RecordNotarisation(blocks[2].vtx[0], a2kmd);
n.height = chainActive.Height();
SendIPC(E_MARSHAL(ss << n));
/*
* Extend proof
*/
std::pair<uint256,MerkleBranch> assetChainProof;
uint256 txid;
// Extend proof to MoMoM
assert(E_UNMARSHAL(RecvIPC(), ss >> txid; ss >> kmd2a));
std::pair<uint256,MerkleBranch> ccProof = GetCrossChainProof(txid, (char*)"symbolA",
2, assetChainProof.first, assetChainProof.second);
};
const char endpoint[] = "ipc://tmpKomodoTestCrossChainSock";
if (!childPid) {
assert(0 == zmq_connect(socket, endpoint));
usleep(20000);
RunTestAssetchain();
exit(0);
}
else {
assert(0 == zmq_bind(socket, endpoint));
RunTestKmd();
int returnStatus;
waitpid(childPid, &returnStatus, 0);
unlink("tmpKomodoTestCrossChainSock");
ASSERT_EQ(0, returnStatus);
}
/*
*
* Assetchain notarisation 2
*
ON_ASSETCHAIN {
a2kmd.blockHash = blocks[4].GetHash();
a2kmd.MoM = komodo_calcMoM(a2kmd.height = chainActive.Height(), a2kmd.MoMDepth = 2);
SendIPC(E_MARSHAL(ss << a2kmd));
}
ON_KMD {
assert(E_UNMARSHAL(RecvIPC(), ss >> a2kmd));
// Grab a coinbase input to fund notarisation
RecordNotarisation(blocks[2].vtx[0], a2kmd);
}
generateBlock(&blocks[5]);
generateBlock(&blocks[6]);
*
* Backnotarisation
*
* This is what will contain the MoMoM which allows us to prove across chains
*
std::vector<uint256> moms;
int assetChainHeight;
ON_KMD {
memset(kmd2a.txHash.begin(), 1, 32); // Garbage but non-null
kmd2a.symbol[0] = 0; // KMD
kmd2a.MoMoM = GetProofRoot((char*)"symbolA", 2, chainActive.Height(), moms, &assetChainHeight);
kmd2a.MoMoMDepth = 0; // Needed?
SendIPC(E_MARSHAL(ss << kmd2a));
}
ON_ASSETCHAIN {
assert(E_UNMARSHAL(RecvIPC(), ss >> kmd2a));
RecordNotarisation(blocks[1].vtx[0], kmd2a);
}
*
* 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.
*
std::pair<uint256,MerkleBranch> assetChainProof;
uint256 txid;
ON_ASSETCHAIN {
txid = blocks[2].vtx[0].GetHash();
// First thing to do is get the proof from the assetchain
assetChainProof = GetAssetchainProof(txid);
SendIPC(E_MARSHAL(ss << txid; ss << assetChainProof));
}
ON_KMD {
// Extend proof to MoMoM
assert(E_UNMARSHAL(RecvIPC(), ss >> txid; ss >> kmd2a));
std::pair<uint256,MerkleBranch> ccProof = GetCrossChainProof(txid, (char*)"symbolA",
2, assetChainProof.first, assetChainProof.second);
}
*/
}
} /* namespace TestCrossChainProof */

25
src/test-komodo/testutils.cpp

@ -6,6 +6,7 @@
#include "key.h"
#include "main.h"
#include "miner.h"
#include "notarisationdb.h"
#include "random.h"
#include "rpcserver.h"
#include "rpcprotocol.h"
@ -33,13 +34,14 @@ CKey notaryKey;
int64_t nMockTime;
extern uint32_t USE_EXTERNAL_PUBKEY;
extern std::string NOTARY_PUBKEY;
void setupChain()
{
SelectParams(CBaseChainParams::REGTEST);
// Settings to get block reward
//NOTARY_PUBKEY = _NOTARY_PUBKEY;
NOTARY_PUBKEY = notaryPubkey;
USE_EXTERNAL_PUBKEY = 1;
mapArgs["-mineraddress"] = "bogus";
COINBASE_MATURITY = 1;
@ -54,6 +56,7 @@ void setupChain()
pblocktree = new CBlockTreeDB(1 << 20, true);
CCoinsViewDB *pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
pnotarisations = new NotarisationDB(1 << 20, true);
InitBlockIndex();
}
@ -65,15 +68,19 @@ void generateBlock(CBlock *block)
params.push_back(1);
uint256 blockId;
SetMockTime(nMockTime++); // 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 {
UniValue out = generate(params, false);
blockId.SetHex(out[0].getValStr());
ASSETCHAINS_SYMBOL[0] = symbolPrefix;
if (block) ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId], false));
} catch (const UniValue& e) {
FAIL() << "failed to create block: " << e.write().data();
}
if (block) ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId]));
}
@ -91,7 +98,7 @@ bool acceptTx(const CTransaction tx, CValidationState &state)
}
static CMutableTransaction spendTx(const CTransaction &txIn, int nOut=0)
CMutableTransaction spendTx(const CTransaction &txIn, int nOut)
{
CMutableTransaction mtx;
mtx.vin.resize(1);
@ -103,6 +110,16 @@ static CMutableTransaction spendTx(const CTransaction &txIn, int nOut=0)
}
std::vector<uint8_t> getSig(const CMutableTransaction mtx, CScript inputPubKey, int nIn)
{
uint256 hash = SignatureHash(inputPubKey, mtx, nIn, SIGHASH_ALL, 0, 0);
std::vector<uint8_t> vchSig;
notaryKey.Sign(hash, vchSig);
vchSig.push_back((unsigned char)SIGHASH_ALL);
return vchSig;
}
/*
* In order to do tests there needs to be inputs to spend.
* This method creates a block and returns a transaction that spends the coinbase.

2
src/test-komodo/testutils.h

@ -22,6 +22,8 @@ void generateBlock(CBlock *block=NULL);
bool acceptTx(const CTransaction tx, CValidationState &state);
void acceptTxFail(const CTransaction tx);
void getInputTx(CScript scriptPubKey, CTransaction &txIn);
CMutableTransaction spendTx(const CTransaction &txIn, int nOut=0);
std::vector<uint8_t> getSig(const CMutableTransaction mtx, CScript inputPubKey, int nIn=0);
#endif /* TESTUTILS_H */

Loading…
Cancel
Save