// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "core.h" #include "util.h" std::string COutPoint::ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n); } void COutPoint::print() const { printf("%s\n", ToString().c_str()); } CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn) { prevout = prevoutIn; scriptSig = scriptSigIn; nSequence = nSequenceIn; } CTxIn::CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn, unsigned int nSequenceIn) { prevout = COutPoint(hashPrevTx, nOut); scriptSig = scriptSigIn; nSequence = nSequenceIn; } std::string CTxIn::ToString() const { std::string str; str += "CTxIn("; str += prevout.ToString(); if (prevout.IsNull()) str += strprintf(", coinbase %s", HexStr(scriptSig).c_str()); else str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); if (nSequence != std::numeric_limits::max()) str += strprintf(", nSequence=%u", nSequence); str += ")"; return str; } void CTxIn::print() const { printf("%s\n", ToString().c_str()); } CTxOut::CTxOut(int64 nValueIn, CScript scriptPubKeyIn) { nValue = nValueIn; scriptPubKey = scriptPubKeyIn; } uint256 CTxOut::GetHash() const { return SerializeHash(*this); } std::string CTxOut::ToString() const { if (scriptPubKey.size() < 6) return "CTxOut(error)"; return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str()); } void CTxOut::print() const { printf("%s\n", ToString().c_str()); } uint256 CTransaction::GetHash() const { return SerializeHash(*this); } uint256 CTransaction::GetUsernameHash() const { return SerializeHash(userName); } std::string CTransaction::ToString() const { std::string str; str += strprintf("CTransaction(hash=%s, ver=%d, message.size=%"PRIszu", userName.size=%"PRIszu", pubKey.size=%"PRIszu")\n", GetHash().ToString().substr(0,10).c_str(), nVersion, message.size(), userName.size(), pubKey.size()); if( message.size() ) { str += " message: " + message.ToString() + "\n"; } else { str += " userName: " + userName.ToString() + "\n"; str += " pubKey: " + pubKey.ToString() + "\n"; } return str; } void CTransaction::print() const { printf("%s", ToString().c_str()); } // Amount compression: // * If the amount is 0, output 0 // * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) // * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) // * call the result n // * output 1 + 10*(9*n + d - 1) + e // * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 // (this is decodable, as d is in [1-9] and e is in [0-9]) uint64 CTxOutCompressor::CompressAmount(uint64 n) { if (n == 0) return 0; int e = 0; while (((n % 10) == 0) && e < 9) { n /= 10; e++; } if (e < 9) { int d = (n % 10); assert(d >= 1 && d <= 9); n /= 10; return 1 + (n*9 + d - 1)*10 + e; } else { return 1 + (n - 1)*10 + 9; } } uint64 CTxOutCompressor::DecompressAmount(uint64 x) { // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 if (x == 0) return 0; x--; // x = 10*(9*n + d - 1) + e int e = x % 10; x /= 10; uint64 n = 0; if (e < 9) { // x = 9*n + d - 1 int d = (x % 9) + 1; x /= 9; // x = n n = x*10 + d; } else { n = x+1; } while (e) { n *= 10; e--; } return n; } #if 0 bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) { /* if (out.n >= vout.size()) return false; if (vout[out.n].IsNull()) return false; undo = CTxInUndo(vout[out.n]); vout[out.n].SetNull(); Cleanup(); if (vout.size() == 0) { undo.nHeight = nHeight; undo.fCoinBase = fCoinBase; undo.nVersion = this->nVersion; } */ return true; } bool CCoins::Spend(int nPos) { CTxInUndo undo; COutPoint out(0, nPos); return Spend(out, undo); } #endif uint256 CBlockHeader::GetHash() const { return Hash(BEGIN(nVersion), END(nNonce)); } uint256 CBlock::BuildMerkleTree() const { vMerkleTree.clear(); BOOST_FOREACH(const CTransaction& tx, vtx) vMerkleTree.push_back(tx.GetHash()); int j = 0; for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { for (int i = 0; i < nSize; i += 2) { int i2 = std::min(i+1, nSize-1); vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); } j += nSize; } return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); } std::vector CBlock::GetMerkleBranch(int nIndex) const { if (vMerkleTree.empty()) BuildMerkleTree(); std::vector vMerkleBranch; int j = 0; for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { int i = std::min(nIndex^1, nSize-1); vMerkleBranch.push_back(vMerkleTree[j+i]); nIndex >>= 1; j += nSize; } return vMerkleBranch; } uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector& vMerkleBranch, int nIndex) { if (nIndex == -1) return 0; BOOST_FOREACH(const uint256& otherside, vMerkleBranch) { if (nIndex & 1) hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); else hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); nIndex >>= 1; } return hash; } void CBlock::print() const { printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", GetHash().ToString().c_str(), nVersion, hashPrevBlock.ToString().c_str(), hashMerkleRoot.ToString().c_str(), nTime, nBits, nNonce, vtx.size()); for (unsigned int i = 0; i < vtx.size(); i++) { printf(" "); vtx[i].print(); } printf(" vMerkleTree: "); for (unsigned int i = 0; i < vMerkleTree.size(); i++) printf("%s ", vMerkleTree[i].ToString().c_str()); printf("\n"); }