Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coinbaser #550

Closed
wants to merge 9 commits into from
3 changes: 3 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ bool AppInit2(int argc, char* argv[])
" -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port> (default: 8332)\n") +
" -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address\n") +
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)\n") +
#ifndef __WXMSW__
" -coinbaser=<cmd> \t " + _("Execute <cmd> to calculate coinbase payees\n") +
#endif
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)\n") +
" -rescan \t " + _("Rescan the block chain for missing wallet transactions\n");

Expand Down
168 changes: 162 additions & 6 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include "net.h"
#include "init.h"
#include "cryptopp/sha.h"

#include <limits.h>

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

Expand Down Expand Up @@ -2652,6 +2655,117 @@ class COrphan
};


#ifndef __WXMSW__
int DoCoinbaser_I(CBlock* pblock, uint64 nTotal, FILE* file)
{
int nCount;
if (fscanf(file, "%d\n", &nCount) != 1)
{
printf("DoCoinbaser(): failed to fscanf count\n");
return -2;
}
pblock->vtx[0].vout.resize(nCount + 1);
uint64 nDistributed = 0;
for (int i = 1; i <= nCount; ++i)
{
uint64 nValue;
if (fscanf(file, "%" PRI64u "\n", &nValue) != 1)
{
printf("DoCoinbaser(): failed to fscanf amount for transaction #%d\n", i);
return -(0x1000 | i);
}
pblock->vtx[0].vout[i].nValue = nValue;
nDistributed += nValue;
char strAddr[35];
if (fscanf(file, "%34s\n", strAddr) != 1)
{
printf("DoCoinbaser(): failed to fscanf address for transaction #%d\n", i);
return -(0x2000 | i);
}
CBitcoinAddress address;
if (!address.SetString(strAddr))
{
printf("DoCoinbaser(): invalid bitcoin address for transaction #%d\n", i);
return -(0x3000 | i);
}
pblock->vtx[0].vout[i].scriptPubKey.SetBitcoinAddress(address);
}
if (nTotal < nDistributed)
{
printf("DoCoinbaser(): attempt to distribute %" PRI64u "/%" PRI64u "\n", nDistributed, nTotal);
return -3;
}
uint64 nMine = nTotal - nDistributed;
printf("DoCoinbaser(): total distributed: %" PRI64u "/%" PRI64u " = %" PRI64u " for me\n", nDistributed, nTotal, nMine);
pblock->vtx[0].vout[0].nValue = nMine;
return 0;
}

int DoCoinbaser(CBlock* pblock, uint64 nTotal)
{
string strCmd = mapArgs["-coinbaser"];
FILE* file = NULL;
if (!strCmd.compare(0, 4, "tcp:"))
{
CAddress addrCoinbaser(strCmd.substr(4), true, 0);
SOCKET hSocket;
if (!ConnectSocket(addrCoinbaser, hSocket))
{
perror("DoCoinbaser(): failed to connect");
return -3;
}
file = fdopen(hSocket, "r+");
if (file)
fprintf(file, "total: %" PRI64u "\n\n", nTotal);
}
else
{

try
{
char strTotal[11];
int nTotalLen = snprintf(strTotal, 11, "%" PRI64u, nTotal);
if (nTotalLen < 1 || nTotalLen > 10)
{
strTotal[0] = '\0';
nTotalLen = 0;
}
string::size_type nPos;
while ((nPos = strCmd.find("%d")) != string::npos)
{
strCmd.replace(nPos, 2, strTotal, nTotalLen);
}
}
catch (...)
{
return 1;
}
file = popen(strCmd.c_str(), "r");

}

if (!file)
{
printf("DoCoinbaser(): failed to popen: %s", strerror(errno));
return -1;
}

int rv;
try
{
rv = DoCoinbaser_I(pblock, nTotal, file);
}
catch (...)
{
rv = 1;
}
pclose(file);
if (rv)
pblock->vtx[0].vout.resize(1);
return rv;
}
#endif

CBlock* CreateNewBlock(CReserveKey& reservekey)
{
CBlockIndex* pindexPrev = pindexBest;
Expand Down Expand Up @@ -2787,7 +2901,12 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
}
}
}
pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
int64 nBlkValue = GetBlockValue(pindexPrev->nHeight+1, nFees);
pblock->vtx[0].vout[0].nValue = nBlkValue;
#ifndef __WXMSW__
if (mapArgs.count("-coinbaser"))
DoCoinbaser(&*pblock, nBlkValue);
#endif

// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
Expand All @@ -2796,21 +2915,58 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
pblock->nBits = GetNextWorkRequired(pindexPrev);
pblock->nNonce = 0;

pblock->print();
return pblock.release();
}


std::map<std::string, CScript> mapAuxCoinbases;

CScript BuildCoinbaseScriptSig(uint64 nTime, unsigned int nExtraNonce, bool *pfOverflow)
{
CScript scriptSig = CScript() << nTime << CBigNum(nExtraNonce);

map<std::string, CScript>::iterator it;
for (it = mapAuxCoinbases.begin() ; it != mapAuxCoinbases.end(); ++it)
scriptSig += (*it).second;

if (scriptSig.size() > 100)
{
scriptSig.resize(100);
if (pfOverflow)
*pfOverflow = true;
}
else
if (pfOverflow)
*pfOverflow = false;

return scriptSig;
}

void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
static uint256 hashPrevBlock;
if (hashPrevBlock != pblock->hashPrevBlock)
static uint64 nPrevTime = 0;
static bool fBackward = false;
uint64 nNow = GetTime();
if (nNow > nPrevTime + 1)
{
nExtraNonce = 0;
hashPrevBlock = pblock->hashPrevBlock;
nPrevTime = nNow;
fBackward = false;
}
else
{
if (nNow < nPrevTime && !fBackward)
{
printf("IncrementExtraNonce: WARNING: nNow moved backward: %d -> %d\n", nPrevTime, nNow);
fBackward = true;
}
if (nExtraNonce == UINT_MAX)
printf("IncrementExtraNonce: WARNING: nExtraNonce overflowing!\n");
++nExtraNonce;
}
++nExtraNonce;
pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nTime << CBigNum(nExtraNonce);
pblock->vtx[0].vin[0].scriptSig = BuildCoinbaseScriptSig(nNow, nExtraNonce);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}

Expand Down
2 changes: 2 additions & 0 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
CBlock* CreateNewBlock(CReserveKey& reservekey);
extern std::map<std::string, CScript> mapAuxCoinbases;
CScript BuildCoinbaseScriptSig(uint64 nTime, unsigned int nExtraNonce, bool *pfOverflow = NULL);
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
Expand Down
30 changes: 30 additions & 0 deletions src/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1480,6 +1480,35 @@ Value validateaddress(const Array& params, bool fHelp)
}


Value setworkaux(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setworkaux <id> [data]\n"
"If [data] is not specified, deletes aux.\n"
);

std::string strId = params[0].get_str();
if (params.size() > 1)
{
std::string strData = params[1].get_str();
std::vector<unsigned char> vchData = ParseHex(strData);
if (vchData.size() * 2 != strData.size())
throw JSONRPCError(-8, "Failed to parse data as hexadecimal");
CScript scriptBackup = mapAuxCoinbases[strId];
mapAuxCoinbases[strId] = CScript(vchData);
bool fOverflow;
BuildCoinbaseScriptSig(0, UINT_MAX, &fOverflow);
if (fOverflow)
throw JSONRPCError(-7, "Change would overflow coinbase script");
}
else
mapAuxCoinbases.erase(strId);

return true;
}


Value getwork(const Array& params, bool fHelp)
{
if (fHelp || params.size() > 1)
Expand Down Expand Up @@ -1640,6 +1669,7 @@ pair<string, rpcfn_type> pCallTable[] =
make_pair("sendmany", &sendmany),
make_pair("gettransaction", &gettransaction),
make_pair("listtransactions", &listtransactions),
make_pair("setworkaux", &setworkaux),
make_pair("getwork", &getwork),
make_pair("listaccounts", &listaccounts),
make_pair("settxfee", &settxfee),
Expand Down