Hush Full Node software. We were censored from Github, this is where all development happens now. https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

254 lines
8.3 KiB

// Copyright (c) 2016-2020 The Hush developers
// Distributed under the GPLv3 software license, see the accompanying
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#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 "cc/CCinclude.h"
#include "main.h"
#include "chain.h"
#include "core_io.h"
#include "crosschain.h"
bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,const CTransaction &txTo,unsigned int nIn);
char *CClib_name();
Eval* EVAL_TEST = 0;
struct CCcontract_info CCinfos[0x100];
extern pthread_mutex_t KOMODO_CC_mutex;
bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
{
EvalRef eval;
pthread_mutex_lock(&KOMODO_CC_mutex);
bool out = eval->Dispatch(cond, tx, nIn);
pthread_mutex_unlock(&KOMODO_CC_mutex);
if ( eval->state.IsValid() != out)
fprintf(stderr,"out %d vs %d isValid\n",(int32_t)out,(int32_t)eval->state.IsValid());
//assert(eval->state.IsValid() == out);
if (eval->state.IsValid()) return true;
std::string lvl = eval->state.IsInvalid() ? "Invalid" : "Error!";
fprintf(stderr, "CC Eval %s %s: %s spending tx %s\n",
EvalToStr(cond->code[0]).data(),
lvl.data(),
eval->state.GetRejectReason().data(),
tx.vin[nIn].prevout.hash.GetHex().data());
if (eval->state.IsError()) fprintf(stderr, "Culprit: %s\n", EncodeHexTx(tx).data());
CTransaction tmp;
if (mempool.lookup(tx.GetHash(), tmp))
{
// This is to remove a payments airdrop if it gets stuck in the mempool.
// Miner will mine 1 invalid block, but doesnt stop them mining until a restart.
// This would almost never happen in normal use.
std::list<CTransaction> dummy;
mempool.remove(tx,dummy,true);
}
return false;
}
/*
* Test the validity of an Eval node
*/
bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
{
struct CCcontract_info *cp;
if (cond->codeLength == 0)
return Invalid("empty-eval");
uint8_t ecode = cond->code[0];
if ( ASSETCHAINS_CCDISABLES[ecode] != 0 )
{
// check if a height activation has been set.
if ( mapHeightEvalActivate[ecode] == 0 || this->GetCurrentHeight() == 0 || mapHeightEvalActivate[ecode] > this->GetCurrentHeight() )
{
fprintf(stderr,"%s evalcode.%d %02x\n",txTo.GetHash().GetHex().c_str(),ecode,ecode);
fprintf(stderr, "ac_ccactivateht: evalcode.%i activates at height.%i vs current height.%i\n", ecode, mapHeightEvalActivate[ecode], this->GetCurrentHeight());
return Invalid("disabled-code, -ac_ccenables didnt include this ecode");
}
}
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength);
if ( ecode >= EVAL_FIRSTUSER && ecode <= EVAL_LASTUSER )
{
if ( ASSETCHAINS_CCLIB.size() > 0 && ASSETCHAINS_CCLIB == CClib_name() )
return CClib_Dispatch(cond,this,vparams,txTo,nIn);
else return Invalid("mismatched -ac_cclib vs CClib_name");
}
cp = &CCinfos[(int32_t)ecode];
if ( cp->didinit == 0 )
{
CCinit(cp,ecode);
cp->didinit = 1;
}
switch ( ecode )
{
case EVAL_IMPORTPAYOUT:
return ImportPayout(vparams, txTo, nIn);
break;
case EVAL_IMPORTCOIN:
return ImportCoin(vparams, txTo, nIn);
break;
default:
return(ProcessCC(cp,this, vparams, txTo, nIn));
break;
}
return Invalid("invalid-code, dont forget to add EVAL_NEWCC to Eval::Dispatch");
}
bool Eval::GetSpendsConfirmed(uint256 hash, std::vector<CTransaction> &spends) const
{
// NOT IMPLEMENTED
return false;
}
bool Eval::GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const
{
return(myGetTransaction(hash, txOut,hashBlock));
/*if (!myGetTransaction(hash, txOut,hashBlock)) {
return(myGetTransaction(hash, txOut,hashBlock));
} else return(true);*/
}
bool Eval::GetTxConfirmed(const uint256 &hash, CTransaction &txOut, CBlockIndex &block) const
{
uint256 hashBlock;
if (!GetTxUnconfirmed(hash, txOut, hashBlock))
return false;
if (hashBlock.IsNull() || !GetBlock(hashBlock, block))
return false;
return true;
}
unsigned int Eval::GetCurrentHeight() const
{
return chainActive.Height();
}
bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const
{
auto r = mapBlockIndex.find(hash);
if (r != mapBlockIndex.end()) {
blockIdx = *r->second;
return true;
}
fprintf(stderr, "CC Eval Error: Can't get block from index\n");
return false;
}
extern int32_t hush_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp);
int32_t Eval::GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const
{
return hush_notaries(pubkeys, height, timestamp);
}
bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const
{
if (tx.vin.size() < 11) return false;
CrosschainAuthority auth;
auth.requiredSigs = 11;
auth.size = GetNotaries(auth.notaries, height, timestamp);
return CheckTxAuthority(tx, auth);
}
// Get MoM from a notarisation tx hash (on HUSH)
bool Eval::GetNotarizationData(const uint256 notaryHash, NotarizationData &data) const
{
CTransaction notarisationTx;
CBlockIndex block;
if (!GetTxConfirmed(notaryHash, notarisationTx, block)) return false;
if (!CheckNotaryInputs(notarisationTx, block.GetHeight(), block.nTime)) return false;
if (!ParseNotarizationOpReturn(notarisationTx, data)) return false;
return true;
}
uint32_t Eval::GetAssetchainsCC() const
{
return ASSETCHAINS_CC;
}
std::string Eval::GetAssetchainsSymbol() const
{
return std::string(SMART_CHAIN_SYMBOL);
}
/*
* Notarization data, ie, OP_RETURN payload in notarisation transactions
*/
bool ParseNotarizationOpReturn(const CTransaction &tx, NotarizationData &data)
{
if (tx.vout.size() < 2) return false;
std::vector<unsigned char> vdata;
if (!GetOpReturnData(tx.vout[1].scriptPubKey, vdata)) return false;
bool out = E_UNMARSHAL(vdata, ss >> data);
return out;
}
// Misc
std::string EvalToStr(EvalCode c)
{
FOREACH_EVAL(EVAL_GENERATE_STRING);
char s[10];
sprintf(s, "0x%x", c);
return std::string(s);
}
uint256 SafeCheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
{
if (nIndex == -1)
return uint256();
for (auto it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it)
{
if (nIndex & 1) {
if (*it == hash) {
// non canonical. hash may be equal to node but never on the right.
return uint256();
}
hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
}
else
hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
nIndex >>= 1;
}
return hash;
}
uint256 GetMerkleRoot(const std::vector<uint256>& vLeaves)
{
bool fMutated;
std::vector<uint256> vMerkleTree;
return BuildMerkleTree(&fMutated, vLeaves, vMerkleTree);
}