Browse Source

implement CScript => string extraction, check username constraits, improve username hash

miguelfreitas
Miguel Freitas 12 years ago
parent
commit
d9fdca340c
  1. 4
      src/bitcoinrpc.cpp
  2. 7
      src/core.cpp
  3. 41
      src/main.cpp
  4. 2
      src/main.h
  5. 15
      src/rpcblockchain.cpp
  6. 2
      src/rpcwallet.cpp
  7. 10
      src/script.cpp
  8. 39
      src/script.h

4
src/bitcoinrpc.cpp

@ -176,10 +176,10 @@ Value stop(const Array& params, bool fHelp) @@ -176,10 +176,10 @@ Value stop(const Array& params, bool fHelp)
if (fHelp || params.size() > 1)
throw runtime_error(
"stop\n"
"Stop Bitcoin server.");
"Stop Twister server.");
// Shutdown will take long enough that the response should get back
StartShutdown();
return "Bitcoin server stopping";
return "Twister server stopping";
}

7
src/core.cpp

@ -80,7 +80,12 @@ uint256 CTransaction::GetHash() const @@ -80,7 +80,12 @@ uint256 CTransaction::GetHash() const
uint256 CTransaction::GetUsernameHash() const
{
return SerializeHash(userName);
if(userName.IsSmallString()) {
return SerializeHash(userName.ExtractSmallString());
}
// [MF] TODO: remove this assert later, it will fail for spammessage.
assert(!"username not small string");
return uint256();
}

41
src/main.cpp

@ -408,6 +408,8 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) @@ -408,6 +408,8 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
CBlock blockTmp;
if (pblock == NULL) {
/* [MF] FIXME: Use GetTransaction to obtain block? */
/*
CCoins coins;
if (pcoinsTip->GetCoins(GetUsernameHash(), coins)) {
CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
@ -417,6 +419,8 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) @@ -417,6 +419,8 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
pblock = &blockTmp;
}
}
*/
return 0;
}
if (pblock) {
@ -452,7 +456,26 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) @@ -452,7 +456,26 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
bool CheckUsername(const std::string &userName, CValidationState &state)
{
if (!userName.size() || userName.size() > 16 )
return state.DoS(10, error("CheckUsername() : username size out of limits"));
BOOST_FOREACH(char c, userName) {
if( isalpha(c) ) {
if( !islower(c) )
return state.DoS(10, error("CheckUsername() : username must be lowercase"));
} else if( isdigit(c) ) {
// digit ok
} else if( isspace(c) ) {
return state.DoS(10, error("CheckUsername() : username spaces not allowed"));
} else if( c == '_' ) {
// underscore ok
} else {
return state.DoS(10, error("CheckUsername() : invalid username character"));
}
}
return true;
}
// [MF] check tx consistency and pow, not duplicated id.
@ -467,10 +490,12 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) @@ -467,10 +490,12 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
} else {
if (tx.userName.empty())
return state.DoS(10, error("CheckTransaction() : username empty"));
if (tx.userName.size() > MAX_USERNAME_SIZE)
return state.DoS(100, error("CheckTransaction() : username too big"));
if (tx.pubKey.empty())
return state.DoS(10, error("CheckTransaction() : pubKey empty"));
if (!tx.userName.IsSmallString())
return state.DoS(10, error("CheckTransaction() : username not smallstring"));
if (!CheckUsername( tx.userName.ExtractSmallString(), state ))
return state.DoS(10, error("CheckTransaction() : username check failed"));
}
// Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
@ -574,7 +599,7 @@ bool CTxMemPool::addUnchecked(const uint256& userhash, CTransaction &tx) @@ -574,7 +599,7 @@ bool CTxMemPool::addUnchecked(const uint256& userhash, CTransaction &tx)
bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive)
{
// Remove transaction from memory pool
{
if( !tx.IsSpamMessage() ){
LOCK(cs);
uint256 hash = tx.GetUsernameHash();
if (mapTx.count(hash))
@ -1095,7 +1120,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C @@ -1095,7 +1120,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
}
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
for (unsigned int i = 0; i < block.vtx.size(); i++) {
for (unsigned int i = 1; i < block.vtx.size(); i++) {
if( pblocktree->HaveTxIndex(block.vtx[i].GetUsernameHash()) )
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"));
@ -1110,16 +1135,16 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C @@ -1110,16 +1135,16 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
int64 nStart = GetTimeMicros();
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
vPos.reserve(block.vtx.size()-1);
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const CTransaction &tx = block.vtx[i];
CTxUndo txundo;
if (!tx.IsSpamMessage())
if (!tx.IsSpamMessage()) {
blockundo.vtxundo.push_back(txundo);
vPos.push_back(std::make_pair(tx.GetUsernameHash(), pos));
}
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64 nTime = GetTimeMicros() - nStart;

2
src/main.h

@ -270,6 +270,8 @@ inline bool AllowFree(double dPriority) @@ -270,6 +270,8 @@ inline bool AllowFree(double dPriority)
return dPriority > COIN * 144 / 250;
}
bool CheckUsername(const std::string &userName, CValidationState &state);
// Context-independent validity checks
bool CheckTransaction(const CTransaction& tx, CValidationState& state);

15
src/rpcblockchain.cpp

@ -55,9 +55,22 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) @@ -55,9 +55,22 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex)
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
Array txs;
BOOST_FOREACH(const CTransaction&tx, block.vtx)
Array txuserhashes;
Array usernames;
std::string spamMessage;
BOOST_FOREACH(const CTransaction&tx, block.vtx) {
txs.push_back(tx.GetHash().GetHex());
if( tx.IsSpamMessage() ) {
spamMessage = tx.message.ExtractPushDataString(0);
} else {
txuserhashes.push_back(tx.GetUsernameHash().GetHex());
usernames.push_back(tx.userName.ExtractSmallString());
}
}
result.push_back(Pair("tx", txs));
result.push_back(Pair("spamMessage", spamMessage));
result.push_back(Pair("userhashes", txuserhashes));
result.push_back(Pair("usernames", usernames));
result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
result.push_back(Pair("bits", HexBits(block.nBits)));

2
src/rpcwallet.cpp

@ -1304,7 +1304,7 @@ Value encryptwallet(const Array& params, bool fHelp) @@ -1304,7 +1304,7 @@ Value encryptwallet(const Array& params, bool fHelp)
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
StartShutdown();
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
return "wallet encrypted; Twister server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
}
class DescribeAddressVisitor : public boost::static_visitor<Object>

10
src/script.cpp

@ -1777,6 +1777,16 @@ bool CScript::IsPayToScriptHash() const @@ -1777,6 +1777,16 @@ bool CScript::IsPayToScriptHash() const
this->at(22) == OP_EQUAL);
}
bool CScript::IsSmallString() const
{
if( !size() || this->at(0) >= OP_PUSHDATA1 )
return false;
unsigned int opSize = this->at(0);
if( this->size() != opSize + 1 )
return false;
return true;
}
class CScriptVisitor : public boost::static_visitor<bool>
{
private:

39
src/script.h

@ -533,6 +533,8 @@ public: @@ -533,6 +533,8 @@ public:
bool IsPayToScriptHash() const;
bool IsSmallString() const;
// Called by IsStandardTx
bool IsPushOnly() const
{
@ -548,6 +550,43 @@ public: @@ -548,6 +550,43 @@ public:
return true;
}
bool ExtractPushData( std::vector< std::vector<unsigned char> > &vData) const
{
vData.clear();
const_iterator pc = begin();
while (pc < end())
{
opcodetype opcode;
std::vector<unsigned char> vch;
if (!GetOp(pc, opcode, vch))
return false;
if (opcode > OP_16)
return false;
vData.push_back(vch);
}
return true;
}
// only for username
std::string ExtractSmallString() const
{
if( !IsSmallString() )
return std::string();
unsigned int opSize = this->at(0);
return std::string((const char*)&(this[1]), opSize);
}
std::string ExtractPushDataString(int n) const
{
std::vector< std::vector<unsigned char> > vData;
if( ExtractPushData(vData) && vData.size() >= n+1 ) {
std::string str((const char*)vData[n].data(), vData[n].size());
return str;
}
return std::string();
}
void SetDestination(const CTxDestination& address);
void SetMultisig(int nRequired, const std::vector<CPubKey>& keys);

Loading…
Cancel
Save