Skip to content

Commit

Permalink
Initial paid smsg code.
Browse files Browse the repository at this point in the history
New -smsgsaddnewkeys option restores the old behaviour of searching for messages on all new keys
Moved stake and combine thresholds to wallet, added setting.
Changed 'watchonly' option of filtertransactions to 'include_watchonly' to match help message.
Fixed filtertransactions when watchonly records exist
AreInputsStandard works for coldstaking scripts
  • Loading branch information
tecnovert committed Nov 7, 2017
1 parent a9d4828 commit 4596cf3
Show file tree
Hide file tree
Showing 32 changed files with 1,178 additions and 400 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Expand Up @@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 15)
define(_CLIENT_VERSION_REVISION, 0)
define(_CLIENT_VERSION_PARTICL, 3)
define(_CLIENT_VERSION_PARTICL, 4)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2017)
Expand Down
2 changes: 1 addition & 1 deletion contrib/gitian-descriptors/gitian-linux.yml
@@ -1,5 +1,5 @@
---
name: "particl-linux-0.15.0.3"
name: "particl-linux-0.15.0.4"
enable_cache: true
suites:
- "trusty"
Expand Down
2 changes: 1 addition & 1 deletion contrib/gitian-descriptors/gitian-osx.yml
@@ -1,5 +1,5 @@
---
name: "particl-osx-0.15.0.3"
name: "particl-osx-0.15.0.4"
enable_cache: true
suites:
- "trusty"
Expand Down
2 changes: 1 addition & 1 deletion contrib/gitian-descriptors/gitian-win.yml
@@ -1,5 +1,5 @@
---
name: "particl-win-0.15.0.3"
name: "particl-win-0.15.0.4"
enable_cache: true
suites:
- "trusty"
Expand Down
7 changes: 1 addition & 6 deletions src/chainparams.h
Expand Up @@ -94,10 +94,8 @@ class CChainParams
uint32_t GetStakeMinConfirmations() const { return nStakeMinConfirmations; }
uint32_t GetTargetSpacing() const { return nTargetSpacing; }
uint32_t GetTargetTimespan() const { return nTargetTimespan; }
uint32_t GetStakeTimestampMask(int nHeight) const { return nStakeTimestampMask; }

int64_t GetStakeCombineThreshold() const { return nStakeCombineThreshold; }
int64_t GetStakeSplitThreshold() const { return nStakeSplitThreshold; }
uint32_t GetStakeTimestampMask(int nHeight) const { return nStakeTimestampMask; }
int64_t GetCoinYearReward(int64_t nTime) const;

const DevFundSettings *GetDevFundSettings(int64_t nTime) const;
Expand Down Expand Up @@ -157,10 +155,7 @@ class CChainParams
uint32_t nTargetSpacing; // targeted number of seconds between blocks
uint32_t nTargetTimespan;

int64_t nStakeCombineThreshold = 1000 * COIN;
int64_t nStakeSplitThreshold = 2 * nStakeCombineThreshold;
uint32_t nStakeTimestampMask = (1 << 4) -1; // 4 bits, every kernel stake hash will change every 16 seconds

int64_t nCoinYearReward = 2 * CENT; // 2% per year

std::vector<CImportedCoinbaseTxn> vImportedCoinbaseTxns;
Expand Down
5 changes: 5 additions & 0 deletions src/net_processing.cpp
Expand Up @@ -1306,7 +1306,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr

vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
nSendVersion = std::min(nVersion, PROTOCOL_VERSION);

// Clear NODE_SMSG service flag if old peer version
if (nVersion < MIN_SMSG_PROTO_VERSION)
nServiceInt &= ~NODE_SMSG;
nServices = ServiceFlags(nServiceInt);

if (!pfrom->fInbound)
{
connman.SetServices(pfrom->addr, nServices);
Expand Down
7 changes: 3 additions & 4 deletions src/policy/policy.cpp
Expand Up @@ -94,7 +94,7 @@ bool IsDust(const CTxOutBase *txout, const CFeeRate& dustRelayFee)
{
if (txout->IsType(OUTPUT_STANDARD))
return (((CTxOutStandard*)txout)->nValue < GetDustThreshold((CTxOutStandard*)txout, minRelayTxFee));
return true;
return false;
};


Expand Down Expand Up @@ -261,13 +261,12 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
if (coin.nType != OUTPUT_STANDARD && coin.nType != OUTPUT_CT)
return false;


std::vector<std::vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
const CScript& prevScript = prev.scriptPubKey;

if (!Solver(prevScript, whichType, vSolutions))
//if (!Solver(prevScript, whichType, vSolutions))
if (!::IsStandard(prevScript, whichType, true))
return false;

if (whichType == TX_SCRIPTHASH)
Expand Down
102 changes: 84 additions & 18 deletions src/pos/kernel.cpp
Expand Up @@ -137,6 +137,18 @@ bool IsConfirmedInNPrevBlocks(const uint256 &hashBlock, const CBlockIndex *pinde
}


static bool CheckAge(const CBlockIndex *pindexTip, const uint256 &hashKernelBlock, int &nDepth)
{
// pindexTip is the current tip of the chain
// hashKernelBlock is the hash of the block containing the kernel transaction

int nRequiredDepth = std::min((int)(Params().GetStakeMinConfirmations()-1), (int)(pindexTip->nHeight / 2));

if (IsConfirmedInNPrevBlocks(hashKernelBlock, pindexTip, nRequiredDepth, nDepth))
return false;
return true;
}

// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CBlockIndex *pindexPrev, const CTransaction &tx, int64_t nTime, unsigned int nBits, uint256 &hashProofOfStake, uint256 &targetProofOfStake)
{
Expand All @@ -148,34 +160,57 @@ bool CheckProofOfStake(const CBlockIndex *pindexPrev, const CTransaction &tx, in
|| tx.vin.size() < 1)
return state.DoS(100, error("%s: malformed-txn %s", __func__, tx.GetHash().ToString()), REJECT_INVALID, "malformed-txn");

CBlock blockKernel; // block containing stake kernel, GetTransaction should only fill the header.
CTransactionRef txKernel;
uint256 hashBlock;
CTransactionRef txPrev;

// Kernel (input 0) must match the stake hash target per coin age (nBits)
const CTxIn &txin = tx.vin[0];

// TODO: Will fail in ContextualCheckBlock if kernel is spent
CBlockIndex *pindex = NULL;
int nDepth;
CScript kernelPubKey;
CAmount amount;

Coin coin;
if (!pcoinsTip->GetCoin(txin.prevout, coin) || coin.IsSpent())
return state.DoS(1, error("%s: prevout-not-available", __func__), REJECT_INVALID, "prevout-not-available");
if (coin.nType != OUTPUT_STANDARD)
return state.DoS(100, error("%s: invalid-prevout", __func__), REJECT_INVALID, "invalid-prevout");
{
// Must find the prevout in the txdb / blocks

CBlockIndex *pindex = chainActive[coin.nHeight];
if (!pindex)
return state.DoS(100, error("%s: invalid-prevout", __func__), REJECT_INVALID, "invalid-prevout");
if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), hashBlock, true)
|| txin.prevout.n >= txPrev->vpout.size())
return state.DoS(1, error("%s: prevout-not-in-chain", __func__), REJECT_INVALID, "prevout-not-in-chain");

int nRequiredDepth = std::min((int)(Params().GetStakeMinConfirmations()-1), (int)(pindexPrev->nHeight / 2));
int nDepth = pindexPrev->nHeight - coin.nHeight;
if (nRequiredDepth > nDepth)
return state.DoS(100, error("%s: Tried to stake at depth %d", __func__, nDepth + 1), REJECT_INVALID, "invalid-stake-depth");
const CTxOutBase *outPrev = txPrev->vpout[txin.prevout.n].get();
if (!outPrev->IsStandardOutput())
return state.DoS(100, error("%s: invalid-prevout", __func__), REJECT_INVALID, "invalid-prevout");

int nDepth;
if (!CheckAge(pindexPrev, hashBlock, nDepth))
return state.DoS(100, error("%s: Tried to stake at depth %d", __func__, nDepth + 1), REJECT_INVALID, "invalid-stake-depth");

kernelPubKey = *outPrev->GetPScriptPubKey();
amount = outPrev->GetValue();
} else
{
if (coin.nType != OUTPUT_STANDARD)
return state.DoS(100, error("%s: invalid-prevout", __func__), REJECT_INVALID, "invalid-prevout");

pindex = chainActive[coin.nHeight];
if (!pindex)
return state.DoS(100, error("%s: invalid-prevout", __func__), REJECT_INVALID, "invalid-prevout");

nDepth = pindexPrev->nHeight - coin.nHeight;
int nRequiredDepth = std::min((int)(Params().GetStakeMinConfirmations()-1), (int)(pindexPrev->nHeight / 2));
if (nRequiredDepth > nDepth)
return state.DoS(100, error("%s: Tried to stake at depth %d", __func__, nDepth + 1), REJECT_INVALID, "invalid-stake-depth");

kernelPubKey = coin.out.scriptPubKey;
amount = coin.out.nValue;
};

const CScript &scriptSig = txin.scriptSig;
const CScriptWitness *witness = &txin.scriptWitness;
ScriptError serror = SCRIPT_ERR_OK;

const CScript &kernelPubKey = coin.out.scriptPubKey;
const CAmount &amount = coin.out.nValue;
std::vector<uint8_t> vchAmount(8);
memcpy(&vchAmount[0], &amount, 8);
// Redundant: all inputs are checked later during CheckInputs
Expand All @@ -198,13 +233,44 @@ bool CheckProofOfStake(const CBlockIndex *pindexPrev, const CTransaction &tx, in
// If Coin owners detect this, they can move their coin to a new address.
if (HasIsCoinstakeOp(kernelPubKey))
{
CAmount nVerify = 0;
for (size_t k = 1; k < tx.vin.size(); ++k)
{
const CTxIn &txin = tx.vin[k];
Coin coin;
if (!pcoinsTip->GetCoin(txin.prevout, coin) || coin.IsSpent())
{
if (!GetTransaction(txin.prevout.hash, txPrev, Params().GetConsensus(), hashBlock, true)
|| txin.prevout.n >= txPrev->vpout.size())
return state.DoS(1, error("%s: prevout-not-in-chain %d", __func__, k), REJECT_INVALID, "prevout-not-in-chain");

const CTxOutBase *outPrev = txPrev->vpout[txin.prevout.n].get();
if (!outPrev->IsStandardOutput())
return state.DoS(100, error("%s: invalid-prevout %d", __func__, k), REJECT_INVALID, "invalid-prevout");

if (kernelPubKey != *outPrev->GetPScriptPubKey())
return state.DoS(100, error("%s: mixed-prevout-scripts %d", __func__, k), REJECT_INVALID, "mixed-prevout-scripts");
amount += outPrev->GetValue();

LogPrint(BCLog::POS, "%s: Input %d of coinstake %s is spent.", k, tx.GetHash().ToString());
} else
{
if (coin.nType != OUTPUT_STANDARD)
return state.DoS(100, error("%s: invalid-prevout %d", __func__, k), REJECT_INVALID, "invalid-prevout");
if (kernelPubKey != coin.out.scriptPubKey)
return state.DoS(100, error("%s: mixed-prevout-scripts %d", __func__, k), REJECT_INVALID, "mixed-prevout-scripts");
amount += coin.out.nValue;
};
};

CAmount nVerify = 0;
for (const auto &txout : tx.vpout)
{
if (!txout->IsType(OUTPUT_STANDARD))
{
if (!txout->IsType(OUTPUT_DATA))
return state.DoS(100, error("%s: bad-output-type", __func__), REJECT_INVALID, "bad-output-type");
continue;

};
const CScript *pOutPubKey = txout->GetPScriptPubKey();

if (pOutPubKey && *pOutPubKey == kernelPubKey)
Expand Down
3 changes: 1 addition & 2 deletions src/primitives/transaction.h
Expand Up @@ -25,7 +25,7 @@ static const uint8_t MAX_PARTICL_TXN_VERSION = 0xBF;

enum OutputTypes
{
OUTPUT_NULL = 0, // marker for CCoinsView
OUTPUT_NULL = 0, // marker for CCoinsView (0.14)
OUTPUT_STANDARD = 1,
OUTPUT_CT = 2,
OUTPUT_RINGCT = 3,
Expand Down Expand Up @@ -849,7 +849,6 @@ class CTransaction
return false;

memcpy(&height, &vData[0], 4);

return true;
}

Expand Down
43 changes: 39 additions & 4 deletions src/rpc/smessage.cpp
Expand Up @@ -445,7 +445,7 @@ UniValue smsgaddkey(const JSONRPCRequest &request)
if (request.fHelp || request.params.size() != 2)
throw std::runtime_error(
"smsgaddkey <address> <pubkey>\n"
"Add address, pubkey pair to database.");
"Add address and matching public key to database.");

if (!fSecMsgEnabled)
throw std::runtime_error("Secure messaging is disabled.");
Expand All @@ -461,12 +461,40 @@ UniValue smsgaddkey(const JSONRPCRequest &request)
result.pushKV("reason", SecureMessageGetString(rv));
} else
{
result.pushKV("result", "Added public key to db.");
result.pushKV("result", "Public key added to db.");
};

return result;
}

UniValue smsgaddlocaladdress(const JSONRPCRequest &request)
{
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"smsgaddlocaladdress <address>\n"
"Enable receiving messages on <address>.\n"
"Key for <address> must exist in the wallet.");

if (!fSecMsgEnabled)
throw std::runtime_error("Secure messaging is disabled.");

std::string addr = request.params[0].get_str();

UniValue result(UniValue::VOBJ);
int rv = SecureMsgAddLocalAddress(addr);
if (rv != 0)
{
result.pushKV("result", "Address not added.");
result.pushKV("reason", SecureMessageGetString(rv));
} else
{
result.pushKV("result", "Receiving messages enabled for address.");
};

return result;
}


UniValue smsggetpubkey(const JSONRPCRequest &request)
{
if (request.fHelp || request.params.size() != 1)
Expand Down Expand Up @@ -567,6 +595,9 @@ UniValue smsgsend(const JSONRPCRequest &request)
bool fTestFee = request.params[5].isNull() ? false : request.params[5].get_bool();
CAmount nFee;

if (fPaid && Params().NetworkID() == "main")
throw std::runtime_error("Paid SMSG not yet active on mainnet.");

CKeyID kiFrom, kiTo;
CBitcoinAddress coinAddress(addrFrom);
if (!coinAddress.IsValid())
Expand Down Expand Up @@ -884,20 +915,23 @@ UniValue smsgbuckets(const JSONRPCRequest &request)

for (it = smsgBuckets.begin(); it != smsgBuckets.end(); ++it)
{
std::set<SecMsgToken>& tokenSet = it->second.setTokens;
std::set<SecMsgToken> &tokenSet = it->second.setTokens;

std::string sBucket = std::to_string(it->first);
std::string sFile = sBucket + "_01.dat";

std::string sHash = std::to_string(it->second.hash);

size_t nActiveMessages = it->second.CountActive();

nBuckets++;
nMessages += tokenSet.size();
nMessages += nActiveMessages;

UniValue objM(UniValue::VOBJ);
objM.pushKV("bucket", sBucket);
objM.pushKV("time", part::GetTimeString(it->first, cbuf, sizeof(cbuf)));
objM.pushKV("no. messages", strprintf("%u", tokenSet.size()));
objM.pushKV("active messages", strprintf("%u", nActiveMessages));
objM.pushKV("hash", sHash);
objM.pushKV("last changed", part::GetTimeString(it->second.timeChanged, cbuf, sizeof(cbuf)));

Expand Down Expand Up @@ -1320,6 +1354,7 @@ static const CRPCCommand commands[] =
{ "smsg", "smsgscanchain", &smsgscanchain, true, {} },
{ "smsg", "smsgscanbuckets", &smsgscanbuckets, true, {} },
{ "smsg", "smsgaddkey", &smsgaddkey, true, {} },
{ "smsg", "smsgaddlocaladdress", &smsgaddlocaladdress, true, {} },
{ "smsg", "smsggetpubkey", &smsggetpubkey, true, {} },
{ "smsg", "smsgsend", &smsgsend, true, {} },
{ "smsg", "smsgsendanon", &smsgsendanon, true, {} },
Expand Down

0 comments on commit 4596cf3

Please sign in to comment.