fix all tests
This commit is contained in:
@@ -147,12 +147,6 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t
|
||||
}
|
||||
|
||||
|
||||
uint32_t Eval::GetCurrentLedgerID() const
|
||||
{
|
||||
return -1; // TODO
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get MoM from a notarisation tx hash (on KMD)
|
||||
*/
|
||||
@@ -171,6 +165,19 @@ bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data)
|
||||
*/
|
||||
bool Eval::GetProofRoot(uint256 kmdNotarisationHash, uint256 &momom) const
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
|
||||
uint32_t Eval::GetAssetchainsCC() const
|
||||
{
|
||||
return ASSETCHAINS_CC;
|
||||
}
|
||||
|
||||
|
||||
std::string Eval::GetAssetchainsSymbol() const
|
||||
{
|
||||
return std::string(ASSETCHAINS_SYMBOL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@ public:
|
||||
virtual bool GetNotarisationData(uint256 notarisationHash, NotarisationData &data) const;
|
||||
virtual bool GetProofRoot(uint256 kmdNotarisationHash, uint256 &momom) const;
|
||||
virtual bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const;
|
||||
virtual uint32_t GetCurrentLedgerID() const;
|
||||
virtual uint32_t GetAssetchainsCC() const;
|
||||
virtual std::string GetAssetchainsSymbol() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -12,30 +12,31 @@
|
||||
*/
|
||||
bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &importTx, unsigned int nIn)
|
||||
{
|
||||
if (importTx.vout.size() == 0) return Invalid("no-vouts");
|
||||
if (importTx.vout.size() < 2)
|
||||
return Invalid("too-few-vouts");
|
||||
|
||||
// params
|
||||
TxProof proof;
|
||||
CTransaction burnTx;
|
||||
if (!E_UNMARSHAL(params, ss >> proof; ss >> burnTx))
|
||||
std::vector<CTxOut> payouts;
|
||||
|
||||
if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
|
||||
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())
|
||||
// It should not be at all malleable
|
||||
if (MakeImportCoinTransaction(proof, burnTx, payouts).GetHash() != importTx.GetHash())
|
||||
return Invalid("non-canonical");
|
||||
|
||||
// burn params
|
||||
uint32_t chain; // todo
|
||||
uint32_t targetCcid;
|
||||
std::string targetSymbol;
|
||||
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())
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash))
|
||||
return Invalid("invalid-burn-tx");
|
||||
|
||||
if (targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol())
|
||||
return Invalid("importcoin-wrong-chain");
|
||||
|
||||
// check burn amount
|
||||
@@ -51,7 +52,7 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &imp
|
||||
}
|
||||
|
||||
// Check burntx shows correct outputs hash
|
||||
if (payoutsHash != SerializeHash(importTx.vout))
|
||||
if (payoutsHash != SerializeHash(payouts))
|
||||
return Invalid("wrong-payouts");
|
||||
|
||||
// Check proof confirms existance of burnTx
|
||||
|
||||
@@ -6,42 +6,48 @@
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
|
||||
/*
|
||||
* Generate ImportCoin transaction.
|
||||
*
|
||||
* Contains an empty OP_RETURN as first output; this is critical for preventing a double
|
||||
* 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.
|
||||
*/
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector<CTxOut> payouts)
|
||||
{
|
||||
std::vector<uint8_t> payload =
|
||||
E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << proof; ss << burnTx);
|
||||
std::vector<uint8_t> payload = E_MARSHAL(ss << EVAL_IMPORTCOIN);
|
||||
CMutableTransaction mtx;
|
||||
mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload));
|
||||
mtx.vout = payouts;
|
||||
auto importData = E_MARSHAL(ss << proof; ss << burnTx);
|
||||
mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << importData));
|
||||
return CTransaction(mtx);
|
||||
}
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, int targetChain, const std::vector<CTxOut> payouts)
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts)
|
||||
{
|
||||
std::vector<uint8_t> opret = E_MARSHAL(ss << VARINT(targetChain); ss << SerializeHash(payouts));
|
||||
std::vector<uint8_t> opret = E_MARSHAL(ss << VARINT(targetCCid);
|
||||
ss << targetSymbol;
|
||||
ss << SerializeHash(payouts));
|
||||
return CTxOut(value, CScript() << OP_RETURN << opret);
|
||||
}
|
||||
|
||||
|
||||
static bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx)
|
||||
bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx,
|
||||
std::vector<CTxOut> &payouts)
|
||||
{
|
||||
CScript scriptSig = importTx.vin[0].scriptSig;
|
||||
auto pc = scriptSig.begin();
|
||||
opcodetype opcode;
|
||||
std::vector<uint8_t> evalScript;
|
||||
int code;
|
||||
bool out = false;
|
||||
if (scriptSig.GetOp(pc, opcode, evalScript))
|
||||
if (pc == scriptSig.end())
|
||||
out = E_UNMARSHAL(evalScript, ss >> VARINT(code); ss >> proof; ss >> burnTx);
|
||||
return code == EVAL_IMPORTCOIN && out;
|
||||
std::vector<uint8_t> vData;
|
||||
GetOpReturnData(importTx.vout[0].scriptPubKey, vData);
|
||||
if (importTx.vout.size() < 1) return false;
|
||||
payouts = std::vector<CTxOut>(importTx.vout.begin()+1, importTx.vout.end());
|
||||
return importTx.vin.size() == 1 &&
|
||||
importTx.vin[0].scriptSig == (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN)) &&
|
||||
E_UNMARSHAL(vData, ss >> proof; ss >> burnTx);
|
||||
}
|
||||
|
||||
|
||||
bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash)
|
||||
{
|
||||
std::vector<uint8_t> burnOpret;
|
||||
if (burnTx.vout.size() == 0) return false;
|
||||
GetOpReturnData(burnTx.vout[0].scriptPubKey, burnOpret);
|
||||
return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid);
|
||||
ss >> targetSymbol;
|
||||
ss >> payoutsHash);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +59,8 @@ CAmount GetCoinImportValue(const CTransaction &tx)
|
||||
{
|
||||
TxProof proof;
|
||||
CTransaction burnTx;
|
||||
if (UnmarshalImportTx(tx, proof, burnTx)) {
|
||||
std::vector<CTxOut> payouts;
|
||||
if (UnmarshalImportTx(tx, proof, burnTx, payouts)) {
|
||||
return burnTx.vout.size() ? burnTx.vout[0].nValue : 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -13,10 +13,13 @@ CAmount GetCoinImportValue(const CTransaction &tx);
|
||||
CTransaction MakeImportCoinTransaction(const TxProof proof,
|
||||
const CTransaction burnTx, const std::vector<CTxOut> payouts);
|
||||
|
||||
CTxOut MakeBurnOutput(CAmount value, int targetChain, const std::vector<CTxOut> payouts);
|
||||
CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector<CTxOut> payouts);
|
||||
|
||||
bool VerifyCoinImport(const CScript& scriptSig,
|
||||
TransactionSignatureChecker& checker, CValidationState &state);
|
||||
bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash);
|
||||
bool UnmarshalImportTx(const CTransaction &importTx, TxProof &proof, CTransaction &burnTx,
|
||||
std::vector<CTxOut> &payouts);
|
||||
|
||||
bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state);
|
||||
|
||||
|
||||
void AddImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs, int nHeight);
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#include "chainparams.h"
|
||||
#include "checkpoints.h"
|
||||
#include "crosschain.h"
|
||||
#include "importcoin.h"
|
||||
#include "base58.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/utils.h"
|
||||
#include "main.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "rpcserver.h"
|
||||
@@ -156,3 +158,126 @@ UniValue calc_MoM(const UniValue& params, bool fHelp)
|
||||
ret.push_back(Pair("MoM",MoM.GetHex()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
UniValue migrate_converttoexport(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 3)
|
||||
throw runtime_error(
|
||||
"migrate_converttoexport \"hexstring\" \"dest_symbol\" \"burn_amount\"\n"
|
||||
"\nConvert a raw transaction to a cross-chain export.\n"
|
||||
"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 vouts, should be passed to "
|
||||
"the \"importtransaction\" method on a KMD node to get the corresponding "
|
||||
"import transaction.\n"
|
||||
);
|
||||
|
||||
if (ASSETCHAINS_CC < 2)
|
||||
throw runtime_error("-ac_cc < 2");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] == 0)
|
||||
throw runtime_error("Must be called on assetchain");
|
||||
|
||||
vector<uint8_t> txData(ParseHexV(params[0], "argument 1"));
|
||||
CMutableTransaction tx;
|
||||
if (!E_UNMARSHAL(txData, ss >> tx))
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
|
||||
|
||||
string targetSymbol = params[1].get_str();
|
||||
if (targetSymbol.size() == 0 || targetSymbol.size() > 32)
|
||||
throw runtime_error("targetSymbol length must be >0 and <=32");
|
||||
|
||||
CAmount burnAmount = params[2].get_int64();
|
||||
{
|
||||
CAmount needed;
|
||||
for (int i=0; i<tx.vout.size(); i++)
|
||||
needed += tx.vout[i].nValue;
|
||||
if (burnAmount < needed)
|
||||
throw runtime_error("burnAmount too small");
|
||||
}
|
||||
|
||||
CTxOut burnOut = MakeBurnOutput(burnAmount, ASSETCHAINS_CC, targetSymbol, tx.vout);
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("vouts", HexStr(E_MARSHAL(ss << tx.vout))));
|
||||
tx.vout.clear();
|
||||
tx.vout.push_back(burnOut);
|
||||
ret.push_back(Pair("exportTx", HexStr(E_MARSHAL(ss << tx))));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The process to migrate funds
|
||||
*
|
||||
* Create a transaction on assetchain:
|
||||
*
|
||||
* generaterawtransaction
|
||||
* migrate_converttoexport
|
||||
* fundrawtransaction
|
||||
* signrawtransaction
|
||||
*
|
||||
* migrate_createimportransaction
|
||||
* migrate_completeimporttransaction
|
||||
*/
|
||||
|
||||
UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 2)
|
||||
throw runtime_error("");
|
||||
|
||||
if (ASSETCHAINS_CC < 2)
|
||||
throw runtime_error("-ac_cc < 2");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] == 0)
|
||||
throw runtime_error("Must be called on assetchain");
|
||||
|
||||
vector<uint8_t> txData(ParseHexV(params[0], "argument 1"));
|
||||
|
||||
CTransaction burnTx;
|
||||
if (!E_UNMARSHAL(txData, ss >> burnTx))
|
||||
throw runtime_error("Couldn't parse burnTx");
|
||||
|
||||
|
||||
vector<CTxOut> payouts;
|
||||
if (!E_UNMARSHAL(ParseHexV(params[0], "argument 2"), ss >> payouts))
|
||||
throw runtime_error("Couldn't parse payouts");
|
||||
|
||||
uint256 txid = burnTx.GetHash();
|
||||
TxProof proof = GetAssetchainProof(burnTx.GetHash());
|
||||
|
||||
CTransaction importTx = MakeImportCoinTransaction(proof, burnTx, payouts);
|
||||
return HexStr(E_MARSHAL(ss << importTx));
|
||||
}
|
||||
|
||||
|
||||
UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error("");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] != 0)
|
||||
throw runtime_error("Must be called on KMD");
|
||||
|
||||
CTransaction importTx;
|
||||
if (!E_UNMARSHAL(ParseHexV(params[0], "argument 2"), ss >> importTx))
|
||||
throw runtime_error("Couldn't parse importTx");
|
||||
|
||||
TxProof proof;
|
||||
CTransaction burnTx;
|
||||
vector<CTxOut> payouts;
|
||||
if (!UnmarshalImportTx(importTx, proof, burnTx, payouts))
|
||||
throw runtime_error("Couldn't parse importTx data");
|
||||
|
||||
std::string targetSymbol;
|
||||
uint32_t targetCCid;
|
||||
uint256 payoutsHash;
|
||||
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash))
|
||||
throw runtime_error("Couldn't parse burnTx data");
|
||||
|
||||
proof = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, proof);
|
||||
|
||||
importTx = MakeImportCoinTransaction(proof, burnTx, importTx.vout);
|
||||
|
||||
return HexStr(E_MARSHAL(ss << importTx));
|
||||
}
|
||||
|
||||
@@ -31,17 +31,19 @@ public:
|
||||
TxProof proof;
|
||||
uint256 MoMoM;
|
||||
CMutableTransaction importTx;
|
||||
uint32_t chainId = 2;
|
||||
uint32_t testCcid = 2;
|
||||
std::string testSymbol = "PIZZA";
|
||||
CAmount amount = 100;
|
||||
|
||||
void SetImportTx() {
|
||||
burnTx.vout.resize(0);
|
||||
burnTx.vout.push_back(MakeBurnOutput(amount, chainId, payouts));
|
||||
MoMoM = burnTx.GetHash(); // TODO: an actual branch
|
||||
burnTx.vout.push_back(MakeBurnOutput(amount, testCcid, testSymbol, payouts));
|
||||
importTx = CMutableTransaction(MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts));
|
||||
MoMoM = burnTx.GetHash(); // TODO: an actual branch
|
||||
}
|
||||
|
||||
uint32_t GetCurrentLedgerID() const { return chainId; }
|
||||
uint32_t GetAssetchainsCC() const { return testCcid; }
|
||||
std::string GetAssetchainsSymbol() const { return testSymbol; }
|
||||
|
||||
bool GetProofRoot(uint256 hash, uint256 &momom) const
|
||||
{
|
||||
@@ -145,7 +147,7 @@ TEST_F(TestCoinImport, testNoVouts)
|
||||
{
|
||||
importTx.vout.resize(0);
|
||||
TestRunCCEval(importTx);
|
||||
EXPECT_EQ("no-vouts", state.GetRejectReason());
|
||||
EXPECT_EQ("too-few-vouts", state.GetRejectReason());
|
||||
}
|
||||
|
||||
|
||||
@@ -172,23 +174,23 @@ TEST_F(TestCoinImport, testInvalidBurnOutputs)
|
||||
MoMoM = burnTx.GetHash(); // TODO: an actual branch
|
||||
CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
|
||||
TestRunCCEval(tx);
|
||||
EXPECT_EQ("invalid-burn-outputs", state.GetRejectReason());
|
||||
EXPECT_EQ("invalid-burn-tx", state.GetRejectReason());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestCoinImport, testInvalidBurnParams)
|
||||
{
|
||||
burnTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(chainId));
|
||||
burnTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << VARINT(testCcid));
|
||||
MoMoM = burnTx.GetHash(); // TODO: an actual branch
|
||||
CTransaction tx = MakeImportCoinTransaction(proof, CTransaction(burnTx), payouts);
|
||||
TestRunCCEval(tx);
|
||||
EXPECT_EQ("invalid-burn-params", state.GetRejectReason());
|
||||
EXPECT_EQ("invalid-burn-tx", state.GetRejectReason());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestCoinImport, testWrongChainId)
|
||||
{
|
||||
chainId = 0;
|
||||
testCcid = 0;
|
||||
TestRunCCEval(importTx);
|
||||
EXPECT_EQ("importcoin-wrong-chain", state.GetRejectReason());
|
||||
}
|
||||
@@ -206,15 +208,24 @@ TEST_F(TestCoinImport, testInvalidBurnAmount)
|
||||
|
||||
TEST_F(TestCoinImport, testPayoutTooHigh)
|
||||
{
|
||||
importTx.vout[0].nValue = 101;
|
||||
importTx.vout[1].nValue = 101;
|
||||
TestRunCCEval(importTx);
|
||||
EXPECT_EQ("payout-too-high", state.GetRejectReason());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestCoinImport, testAmountInOpret)
|
||||
{
|
||||
importTx.vout[0].nValue = 1;
|
||||
TestRunCCEval(importTx);
|
||||
EXPECT_EQ("non-canonical", state.GetRejectReason());
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_F(TestCoinImport, testInvalidPayouts)
|
||||
{
|
||||
importTx.vout[0].nValue = 40;
|
||||
importTx.vout[1].nValue = 40;
|
||||
importTx.vout.push_back(importTx.vout[0]);
|
||||
TestRunCCEval(importTx);
|
||||
EXPECT_EQ("wrong-payouts", state.GetRejectReason());
|
||||
|
||||
@@ -47,6 +47,9 @@ void setupChain()
|
||||
COINBASE_MATURITY = 1;
|
||||
// Global mock time
|
||||
nMockTime = GetTime();
|
||||
|
||||
// Unload
|
||||
UnloadBlockIndex();
|
||||
|
||||
// Init blockchain
|
||||
ClearDatadirCache();
|
||||
|
||||
Reference in New Issue
Block a user