create functions in main.cpp which can decode and strip NCC commands from a txout.scriptPubKey, and create functions in rpcwallet.cpp which can create transactions with NCC commands. change tests to pass given NCC parameters, add CLAIM_NAME as a script command in script/script.h, and add a few printouts that occur during transaction spends which should be removed later

This commit is contained in:
Jimmy Kiselak 2015-01-05 11:43:07 -05:00
parent aec93c1245
commit d4d3ab8115
12 changed files with 241 additions and 22 deletions

View file

@ -17,7 +17,7 @@ static const CAmount COIN = 100000000;
static const CAmount CENT = 1000000;
/** No amount larger than this (in satoshi) is valid */
static const CAmount MAX_MONEY = 21000000 * COIN;
static const CAmount MAX_MONEY = 21000000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
/** Type-safe wrapper class to for fee rates

View file

@ -120,12 +120,12 @@ public:
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
nDefaultPort = 8333;
bnProofOfWorkLimit = ~uint256(0) >> 1;
nSubsidyHalvingInterval = 210000;
nSubsidyHalvingInterval = 2100000;
nEnforceBlockUpgradeMajority = 750;
nRejectBlockOutdatedMajority = 950;
nToCheckBlockUpgradeMajority = 1000;
nMinerThreads = 2;
nTargetTimespan = 30 * 60;//14 * 24 * 60 * 60; // two weeks
nTargetTimespan = 30 * 60 * 10;//14 * 24 * 60 * 60; // two weeks
nTargetSpacing = 30;
/**
@ -170,10 +170,10 @@ public:
}*/
hashGenesisBlock = genesis.GetHash();
printf("%s\n", hashGenesisBlock.GetHex().c_str());
//printf("%s\n", hashGenesisBlock.GetHex().c_str());
//assert(hashGenesisBlock == uint256("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(hashGenesisBlock == uint256("0x008c55867210a8154af697b7776c6b6cdb26972381eac9f84d18a491374464a3"));
printf("%s\n", genesis.hashMerkleRoot.GetHex().c_str());
//printf("%s\n", genesis.hashMerkleRoot.GetHex().c_str());
//assert(genesis.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
assert(genesis.hashMerkleRoot == uint256("0xa7d51d407092059a2beeffab22e65d6176cfb3c33b93515109480aa7c81c9141"));

View file

@ -6,6 +6,8 @@
#include "random.h"
#include "util.h"
#include <assert.h>
/**
@ -36,6 +38,7 @@ bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) {
return false;
if (vout[out.n].IsNull())
return false;
LogPrintf("In CCoins::Spend for output %d in transaction %s\n", out.n, out.hash.GetHex().c_str());
undo = CTxInUndo(vout[out.n]);
vout[out.n].SetNull();
Cleanup();

View file

@ -616,11 +616,76 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams)
{
CScript::const_iterator pc = scriptIn.begin();
return DecodeNCCScript(scriptIn, op, vvchParams, pc);
}
bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc)
{
opcodetype opcode;
if (!scriptIn.GetOp(pc, opcode))
{
return false;
}
if (opcode != OP_CLAIM_NAME)
{
return false;
}
op = opcode;
std::vector<unsigned char> vchName;
std::vector<unsigned char> vchValue;
// The correct format is:
// OP_CLAIM_NAME vchName vchValue OP_DROP2 OP_DROP pubkeyscript
// All others are invalid.
if (!scriptIn.GetOp(pc, opcode, vchName) || opcode < 0 || opcode > OP_PUSHDATA4)
{
return false;
}
if (!scriptIn.GetOp(pc, opcode, vchValue) || opcode < 0 || opcode > OP_PUSHDATA4)
{
return false;
}
if (!scriptIn.GetOp(pc, opcode) || opcode != OP_2DROP)
{
return false;
}
if (!scriptIn.GetOp(pc, opcode) || opcode != OP_DROP)
{
return false;
}
vvchParams.push_back(vchName);
vvchParams.push_back(vchValue);
return true;
}
CScript StripNCCScriptPrefix(const CScript& scriptIn)
{
int op;
std::vector<std::vector<unsigned char> > vvchParams;
CScript::const_iterator pc = scriptIn.begin();
if (!DecodeNCCScript(scriptIn, op, vvchParams, pc))
{
return scriptIn;
}
return CScript(pc, scriptIn.end());
}
bool IsStandardTx(const CTransaction& tx, string& reason)
{
AssertLockHeld(cs_main);
// TODO: We may have a different version here
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
reason = "version";
return false;
@ -680,7 +745,10 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
unsigned int nDataOut = 0;
txnouttype whichType;
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
if (!::IsStandard(txout.scriptPubKey, whichType)) {
const CScript& scriptPubKey = StripNCCScriptPrefix(txout.scriptPubKey);
if (!::IsStandard(scriptPubKey, whichType)) {
reason = "scriptpubkey";
return false;
}
@ -744,7 +812,8 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
vector<vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
const CScript& prevScript = prev.scriptPubKey;
const CScript& prevScript = StripNCCScriptPrefix(prev.scriptPubKey);
if (!Solver(prevScript, whichType, vSolutions))
return false;
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
@ -814,8 +883,9 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]);
if (prevout.scriptPubKey.IsPayToScriptHash())
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
const CScript& scriptPubKey = StripNCCScriptPrefix(prevout.scriptPubKey);
if (scriptPubKey.IsPayToScriptHash())
nSigOps += scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
}
return nSigOps;
}
@ -1712,6 +1782,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
}
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
// TODO: This seems like a good place to actually change the
// TODO: tree of NCCs and make the CUndo vector for those changes.
vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
@ -2516,6 +2589,9 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
}
}
// TODO: This looks like a good place to check the "merkle" root of the
// TODO: NCC tree that will result from applying this block
return true;
}

View file

@ -304,6 +304,11 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason);
bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams);
bool DecodeNCCScript(const CScript& scriptIn, int& op, std::vector<std::vector<unsigned char> >& vvchParams, CScript::const_iterator& pc);
CScript StripNCCScriptPrefix(const CScript& scriptIn);
/** Undo information for a CBlock */
class CBlockUndo
{

View file

@ -310,6 +310,74 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
return ret;
}
void ClaimName(const std::vector<unsigned char> vchName, const std::vector<unsigned char> vchValue, CAmount nAmount, CWalletTx& wtxNew)
{
// Check amount
if (nAmount <= 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
if (nAmount > pwalletMain->GetBalance())
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
string strError;
if (pwalletMain->IsLocked())
{
strError = "Error: Wallet locked, unable to create transaction!";
LogPrintf("SendMoney() : %s", strError);
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
//Get new address
CPubKey newKey;
if (!pwalletMain->GetKeyFromPool(newKey))
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
CScript scriptPubKey = GetScriptForDestination(CTxDestination(newKey.GetID()));
CScript claimScript = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << scriptPubKey;
CReserveKey reservekey(pwalletMain);
CAmount nFeeRequired;
if (!pwalletMain->CreateTransaction(claimScript, nAmount, wtxNew, reservekey, nFeeRequired, strError))
{
if (nAmount + nFeeRequired > pwalletMain->GetBalance())
strError = strprintf("Error: This transaction requires a transaction fee of at least %s because if its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
LogPrintf("ClaimName() : %s\n", strError);
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might hapen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
Value claimname(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
"claimname \"name\" \"value\" amount\n"
"\nCreate a transaction which issues a claim assigning a value to a name. The claim will be authoritative if the transaction amount is greater than the transaction amount of all other unspent transactions which issue a claim over the same name, and it will remain authoritative as long as it remains unspent. The amount is a real and is rounded to the nearest 0.00000001\n"
+ HelpRequiringPassphrase() +
"\nArguments:\n"
"1. \"name\" (string, required) The name to be assigned the value.\n"
"2. \"value\" (string, required) The value to assign to the name.\n"
"3. \"amount\n (numeric, required) The amount in ncc to send. eg 0.1\n"
"\nResult:\n"
"\"transactionid\" (string) The transaction id.\n"
);
string sName = params[0].get_str();
string sValue = params[1].get_str();
std::vector<unsigned char> vchName (sName.begin(), sName.end());
std::vector<unsigned char> vchValue (sValue.begin(), sValue.end());
CAmount nAmount = AmountFromValue(params[2]);
CWalletTx wtx;
EnsureWalletIsUnlocked();
ClaimName(vchName, vchValue, nAmount, wtx);
return wtx.GetHash().GetHex();
}
void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew)
{
// Check amount

View file

@ -29,6 +29,7 @@ enum opcodetype
// push value
OP_0 = 0x00,
OP_FALSE = OP_0,
OP_CLAIM_NAME = OP_0,
OP_PUSHDATA1 = 0x4c,
OP_PUSHDATA2 = 0x4d,
OP_PUSHDATA4 = 0x4e,

View file

@ -18,21 +18,21 @@ BOOST_AUTO_TEST_SUITE(Checkpoints_tests)
BOOST_AUTO_TEST_CASE(sanity)
{
uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d");
uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe");
BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111));
BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444));
// uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d");
// uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe");
// BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111));
// BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444));
// Wrong hashes at checkpoints should fail:
BOOST_CHECK(!Checkpoints::CheckBlock(11111, p134444));
BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111));
// BOOST_CHECK(!Checkpoints::CheckBlock(11111, p134444));
// BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111));
// ... but any hash not at a checkpoint should succeed:
BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p134444));
BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111));
// BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p134444));
// BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111));
BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444);
// BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444);
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -18,7 +18,8 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test)
nSum += nSubsidy * 1000;
BOOST_CHECK(MoneyRange(nSum));
}
BOOST_CHECK(nSum == 2099999997690000ULL);
//BOOST_CHECK(nSum == 2099999997690000ULL);
BOOST_CHECK(nSum == 20781250000000000LL);
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -12,7 +12,7 @@
BOOST_AUTO_TEST_SUITE(miner_tests)
static
/*static
struct {
unsigned char extranonce;
unsigned int nonce;
@ -45,6 +45,41 @@ struct {
{1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce},
{2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e},
{2, 0xbbbeb305}, {2, 0xfe1c810a},
};*/
static
struct {
unsigned char extranonce;
unsigned int nonce;
} blockinfo[] = {
{4, 0x00000002}, {2, 0x00000002}, {1, 0x00000000}, {1, 0x00000001}, //0
{2, 0x00000001}, {2, 0x00000002}, {1, 0x00000000}, {2, 0x0000000b}, //4
{2, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}, {2, 0x00000001}, //8
{2, 0x00000000}, {1, 0x00000000}, {2, 0x00000000}, {2, 0x00000001}, //12
{1, 0x00000000}, {2, 0x00000004}, {1, 0x00000000}, {1, 0x00000000}, //16
{3, 0x00000002}, {2, 0x00000000}, {2, 0x00000000}, {1, 0x00000000}, //20
{2, 0x00000000}, {1, 0x00000002}, {2, 0x00000000}, {2, 0x00000000}, //24
{2, 0x00000000}, {2, 0x00000001}, {2, 0x00000000}, {2, 0x00000000}, //28
{1, 0x00000000}, {2, 0x00000001}, {2, 0x00000000}, {1, 0x00000000}, //32
{2, 0x00000001}, {1, 0x00000000}, {2, 0x00000001}, {1, 0x00000000}, //36
{1, 0x00000001}, {3, 0x00000000}, {2, 0x00000000}, {5, 0x00000002}, //40
{1, 0x00000001}, {5, 0x00000000}, {1, 0x00000005}, {1, 0x00000000}, //44
{1, 0x00000000}, {2, 0x00000002}, {1, 0x00000002}, {1, 0x00000000}, //48
{1, 0x00000000}, {1, 0x00000000}, {5, 0x00000001}, {5, 0x00000000}, //52
{1, 0x00000000}, {1, 0x00000000}, {6, 0x00000000}, {2, 0x00000001}, //56
{2, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {1, 0x00000002}, //60
{2, 0x00000001}, {2, 0x00000000}, {1, 0x00000003}, {1, 0x00000001}, //64
{1, 0x00000000}, {5, 0x00000000}, {5, 0x00000002}, {1, 0x00000001}, //68
{1, 0x00000001}, {2, 0x00000000}, {2, 0x00000001}, {1, 0x00000003}, //72
{2, 0x00000002}, {1, 0x00000000}, {2, 0x00000000}, {2, 0x00000006}, //76
{1, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {5, 0x00000000}, //80
{1, 0x00000001}, {1, 0x00000001}, {1, 0x00000000}, {1, 0x00000002}, //84
{1, 0x00000000}, {1, 0x00000000}, {1, 0x00000002}, {2, 0x00000001}, //88
{0, 0x00000003}, {1, 0x00000004}, {2, 0x00000000}, {2, 0x00000001}, //92
{2, 0x00000000}, {1, 0x00000002}, {1, 0x00000000}, {1, 0x00000002}, //96
{1, 0x00000000}, {1, 0x00000003}, {1, 0x00000000}, {5, 0x00000000}, //100
{2, 0x00000000}, {1, 0x00000000}, {1, 0x00000001}, {1, 0x00000001}, //104
{2, 0x00000000}, {2, 0x00000002}, //108
};
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
@ -80,6 +115,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
txFirst.push_back(new CTransaction(pblock->vtx[0]));
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nNonce = blockinfo[i].nonce;
/*bool fFound = false;
for (int j = 0; !fFound; j++)
{
pblock->nNonce = j;
if (CheckProofOfWork(pblock->GetHash(), pblock->nBits))
{
fFound = true;
std::cout << "Block number: " << i << std::endl;
std::cout << "Nonce: " << std::hex << pblock->nNonce << std::dec << std::endl;
}
}*/
CValidationState state;
BOOST_CHECK(ProcessNewBlock(state, NULL, pblock));
BOOST_CHECK(state.IsValid());
@ -198,6 +244,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
delete pblocktemplate;
mempool.clear();
/* This has been removed because we don't have that many blocks in the active chain yet.
It should be returned when we do.
// subsidy changing
int nHeight = chainActive.Height();
chainActive.Tip()->nHeight = 209999;
@ -207,6 +255,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
delete pblocktemplate;
chainActive.Tip()->nHeight = nHeight;
*/
// non-final txs in mempool
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);

View file

@ -373,6 +373,18 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
BOOST_CHECK(!IsStandardTx(t, reason));
// NCC transactions
t.vout.resize(1);
string sName = "testname";
string sValue = "testvalue";
std::vector<unsigned char> vchName (sName.begin(), sName.end());
std::vector<unsigned char> vchValue (sValue.begin(), sValue.end());
CScript scriptPubKey = CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP;
t.vout[0].scriptPubKey = scriptPubKey + GetScriptForDestination(key.GetPubKey().GetID());
t.vout[0].nValue = 10*COIN;
BOOST_CHECK(IsStandardTx(t, reason));
}
BOOST_AUTO_TEST_SUITE_END()

View file

@ -15,11 +15,15 @@
using namespace std;
void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
if (coins.IsPruned())
if (coins.IsPruned()) {
LogPrintf("BatchWriteCoins erasing %s\n", hash.GetHex().c_str());
batch.Erase(make_pair('c', hash));
else
}
else {
LogPrintf("BatchWriteCoins writing %s\n", hash.GetHex().c_str());
batch.Write(make_pair('c', hash), coins);
}
}
void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
batch.Write('B', hash);